首页 > 解决方案 > 使用 StreamBuilder 代替 FeatureBuilder 来避免 Firestore 中的 whereIn 10 限制

问题描述

我想获取特定用户喜欢的帖子并在交错网格视图中显示它们。我可以在 FutureBuilder 中做到这一点。但是在 FutureBuilder 中,由于whereIn10 的限制,我无法获取更多。我知道它可以使用 StreamBuilder 来实现。但我很无奈,不知道该怎么做。

这是我的 Firebase 收藏。

在此处输入图像描述

下面是获取数据的代码:


  final FirebaseFirestore firestore = FirebaseFirestore.instance;
  getData() async {
    SharedPreferences sp = await SharedPreferences.getInstance();
    String _uid = sp.getString('uid');

    final DocumentReference ref = firestore.collection('users').doc(_uid);
    DocumentSnapshot snap = await ref.get();
    List d = snap['loved items'];
    List filteredData = [];
    if (d.isNotEmpty) {
      await firestore
          .collection('contents')
          .where('timestamp', whereIn: d)
          .get()
          .then((QuerySnapshot snap) {
        filteredData = snap.docs;
      });
    }

    notifyListeners();
    return filteredData;
  }

这是 FutureBuilder 代码:

body: sb.guestUser == true
            ? EmptyPage(
                icon: FontAwesomeIcons.heart,
                title: 'No wallpapers found.\n Sign in to access this feature',
              )
            : FutureBuilder(
                future: context.watch<BookmarkBloc>().getData(),
                builder: (BuildContext context, AsyncSnapshot snapshot) {
                  if (snapshot.hasData) {
                    if (snapshot.data.length == 0)
                      return EmptyPage(
                        icon: FontAwesomeIcons.heart,
                        title: 'No wallpapers found',
                      );
                    return _buildList(snapshot);
                  } else if (snapshot.hasError) {
                    return Center(
                      child: Text(snapshot.error),
                    );
                  }

                  return Center(
                    child: CupertinoActivityIndicator(),
                  );
                },
              ),
      ),
    );
  }

  Widget _buildList(snapshot) {
    return StaggeredGridView.countBuilder(
      crossAxisCount: 4,
      itemCount: snapshot.data.length,
      itemBuilder: (BuildContext context, int index) {
        List d = snapshot.data;

        return InkWell(
          child: Stack(
            children: <Widget>[
              Hero(
                  tag: 'bookmark$index',
                  child: cachedImage(d[index]['image url'])),
              Positioned(
                bottom: 15,
                left: 12,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Text(
                      d[index]['category'],
                      style: TextStyle(color: Colors.white, fontSize: 18),
                    )
                  ],
                ),
              ),
              Positioned(
                right: 10,
                top: 20,
                child: Row(
                  children: [
                    Icon(Icons.favorite,
                        color: Colors.white.withOpacity(0.5), size: 25),
                    Text(
                      d[index]['loves'].toString(),
                      style: TextStyle(
                          color: Colors.white.withOpacity(0.7),
                          fontSize: 16,
                          fontWeight: FontWeight.w600),
                    ),
                  ],
                ),
              ),
            ],
          ),
          onTap: () {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => DetailsPage(
                          tag: 'bookmark$index',
                          imageUrl: d[index]['image url'],
                          catagory: d[index]['category'],
                          timestamp: d[index]['timestamp'],
                        )));
          },
        );
      },
      staggeredTileBuilder: (int index) =>
          new StaggeredTile.count(2, index.isEven ? 4 : 3),
      mainAxisSpacing: 10,
      crossAxisSpacing: 10,
      padding: EdgeInsets.all(15),
    );
  }
}

我提到了互联网,但我并不完全知道如何将 FutureBuilder 转换为返回快照列表的 StreamBuilder。还有其他方法吗?

标签: flutterdartgoogle-cloud-firestorestream-builderflutter-futurebuilder

解决方案


首先,“ whereIn10 的限制”是 Firestore 的硬约束。这意味着无论您使用FutureBuilderStreamBuilder,限制 10 的约束仍然适用。

现在,如果您仍想切换到StreamBuilder

StreamBuilder<QuerySnapshot>(
      stream: _yourStream,
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {

您需要调整它以成为 Stream

await firestore
          .collection('contents')
          .where('timestamp', whereIn: d)
          .get()
          .then((QuerySnapshot snap) {
        filteredData = snap.docs;
      });

您需要更改.get( ).snapshots()并需要使用snapshot.data.docs.map

此处的流示例中的更多详细信息https://firebase.flutter.dev/docs/firestore/usage

编辑:

关于 10 项硬约束:根据您的具体项目,您可以:

  • 多次查询然后在您的应用程序中本地合并(同时删除重复项),或

  • 另一种解决方案是在您的应用程序中做一些过滤客户端(基本上,从 FireStore 带来更多并在颤振中过滤),或者

  • 另一种解决方案是创建由其他字段组合的新字段(例如,在您的情况下,它可能是“月”或“周数”,因此您在 1 个条件下有一周的时间而不是 7 天)


推荐阅读