使用 StreamBuilder 而不是 FeatureBuilder 来避免 Firestore 中的 whereIn 10 限制
Posted
技术标签:
【中文标题】使用 StreamBuilder 而不是 FeatureBuilder 来避免 Firestore 中的 whereIn 10 限制【英文标题】:Using StreamBuilder instead of FeatureBuilder to avoid whereIn 10 Limit in Firestore 【发布时间】:2021-12-05 18:08:13 【问题描述】:我想获取特定用户喜欢的帖子并在交错网格视图中显示它们。我可以在 FutureBuilder 中做到这一点。但是在 FutureBuilder 中,由于 whereIn
的限制为 10,我无法获取更多。我知道使用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。还有其他方法吗?
【问题讨论】:
【参考方案1】:首先,“whereIn
限制为 10”是 Firestore 硬约束。这意味着无论您使用FutureBuilder
还是StreamBuilder
,这个limit-of-10 约束仍然适用。
现在,如果你还想切换到StreamBuilder
StreamBuilder<QuerySnapshot>(
stream: _yourStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot)
您需要调整它以成为流
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 中获取更多内容并在 Flutter 中进行过滤),或者
另一种解决方案是创建由其他字段组合而成的新字段(例如,在您的情况下,它可能是“月”或“weekNumber”,因此您在 1 种情况下有一周而不是 7 天)
【讨论】:
如果您还需要其他东西,请告诉我 感谢您的回答。我试过你的建议。但正如你所说,即使我使用 streamBuilder 它也会抛出同样的错误'in' filters support a maximum of 10 elements in the value
有没有其他方法可以解决这个问题?我想把它们都拿来。
不,这 10 项是硬约束。我现在将在我的回答中添加一些提示。如果您认为它回答了您的问题,请考虑“接受”我的回答【参考方案2】:
Firestore 不允许您使用超过 10 条记录进行数组成员资格查询。如果您检查此documentation,您将看到:
where() 方法接受三个参数:一个要过滤的字段,一个 比较运算符和一个值。众多中的“in”运算符 where() 方法的比较运算符用于组合最多 10 个 具有逻辑 OR 的同一字段上的相等 (==) 子句。
如果您使用超过 10 条记录,Firestore 将不会接受它,您会收到错误消息。 我建议您将“d”数组分成多个数组,最多包含 10 条记录以进行查询,这将允许 Firestore 在其限制范围内操作 whereIn 并且它会起作用。
还有一个类似的 *** 线程建议使用 chunkSizeCollection 将数组拆分为 10 个元素的块。
【讨论】:
以上是关于使用 StreamBuilder 而不是 FeatureBuilder 来避免 Firestore 中的 whereIn 10 限制的主要内容,如果未能解决你的问题,请参考以下文章
使本地图像直接出现在聊天中,而不是等待网络图像(Streambuilder / Firebase)
为啥使用 InheritedWidget 而我们可以使用 Broadcast Streams | StreamBuilder 和静态变量
如何在 StreamBuilder 中更新 Flutter Cards 而无需重置状态?