You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore查询组合难题:如何筛选非当前用户创建且未接收过当前用户报价的请求文档

Firestore查询组合难题:如何筛选非当前用户创建且未接收过当前用户报价的请求文档

嗨,我完全理解你的困扰——Firestore的查询规则有时候确实会让人卡壳,尤其是whereIn/whereNotIn的数量限制这块。先帮你理清楚问题出在哪:

Firestore的查询规则明确规定:一个查询里最多只能包含一个whereIn或者whereNotIn过滤器。你现在的代码里已经用了两个whereIn(city.name和profesion.name),再加上注释里的offeredBy的whereNotIn,自然就触发了!hasIn的错误。

针对你的需求,我给你两个可行的解决方案,你可以根据自己的业务场景选择:

方案一:客户端过滤(最直接的快速解决方案)

既然Firestore不允许三个whereIn/whereNotIn组合,那我们可以先获取符合前几个条件的请求,再在客户端手动过滤掉你已经发过报价的文档。为了避免过滤后结果不足5个,建议你稍微提高查询的limit数量,比如设为10:

final currentUid = firebaseAuth.currentUser!.uid;
final queryResult = await requestsRef
  .where('userId', isNotEqualTo: currentUid)
  .where('city.name', whereIn: user.cities)
  .where(
    Filter.and(
      Filter('profesion.name', whereIn: user.profesions),
      Filter('type', isEqualTo: requestTypeEnum.approved.name),
    ),
  )
  .limit(10) // 多取一些数据,防止客户端过滤后不够5个
  .get();

// 客户端过滤:排除offeredBy数组中包含当前用户UID的文档
final filteredRequests = queryResult.docs.where((doc) {
  final offeredByList = doc.data()['offeredBy'] as List<String>?;
  // 如果offeredBy不存在,或者不包含当前UID,就保留该文档
  return offeredByList == null || !offeredByList.contains(currentUid);
}).take(5).toList(); // 最终只取前5个符合要求的

优缺点分析

  • ✅ 优点:不需要修改现有数据结构,代码改动小,快速实现需求
  • ❌ 缺点:如果符合前置条件的请求中,大部分都是你已经报价过的,可能需要多次查询才能凑够5个结果;如果数据量极大,客户端过滤会有轻微性能损耗(但对于limit10这种量级几乎可以忽略)

方案二:调整数据结构(适合大数据量场景)

如果你的业务中用户发送的报价数量很多,或者客户端过滤的性能无法满足需求,可以考虑调整数据结构来规避whereIn的限制:

你可以在当前用户的Firestore文档中添加一个数组字段sentOfferRequestIds,用来存储所有你已经发送过报价的请求ID。然后查询时分为两步:

  1. 先获取当前用户的sentOfferRequestIds数组
  2. 在请求查询中添加where('requestId', whereNotIn: sentOfferRequestIds)(注意:Firestore的whereNotIn最多支持10个值,如果你的报价超过10个,这个方法就不适用了,需要改用批量查询)

不过这个方案需要你在发送报价时,同时更新用户文档的sentOfferRequestIds数组,额外维护一份数据,适合数据量较大且对性能要求高的场景。

总结

对于你的场景来说,方案一(客户端过滤)是最快速且成本最低的解决方案,完全能满足你当前的需求。如果后续业务规模扩大,再考虑方案二或者更复杂的分区查询方案。

备注:内容来源于stack exchange,提问作者Matias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 07:44:28