【问题标题】:Firestore multiple range queryFirestore 多范围查询
【发布时间】:2019-11-06 11:17:05
【问题描述】:

假设我有一系列汽车,我想按price 范围和year 范围过滤它们。我知道 Firestore 由于性能原因有严格的限制,所以类似于:

db.collection("products")
  .where('price','>=', 70000)
  .where('price','<=', 90000)
  .where('year','>=', 2015)
  .where('year','<=', 2018)

会抛出错误:

查询无效。带有不等式( 或 >=)的所有 where 过滤器必须位于同一字段中。

那么有没有其他方法可以在没有本地数据管理的情况下执行这种查询?也许是某种索引或棘手的数据组织?

【问题讨论】:

    标签: firebase nosql google-cloud-firestore


    【解决方案1】:

    错误消息和文档对此非常明确:Firestore 查询只能对单个字段执行范围过滤。由于您尝试过滤 priceyear 的范围,因此在单个 Firestore 查询中这是不可能的。

    有两种常见的解决方法:

    1. 对查询中的一个字段和客户端代码中的另一个字段执行过滤。
    2. 以某种方式将两个范围的值组合到一个字段中,使您的用例可以使用一个字段。这是非常重要的,据我所知,这种组合的唯一成功示例是使用 geohashes 过滤纬度和经度。

    鉴于这两者之间的努力不同,我建议选择第一个选项。

    第三种选择是对您的数据进行不同的建模,以便更轻松地实施您的用例。最直接的实现是将 2015-2018 年的所有产品放入一个集合中。然后您可以使用db.collection("products-2015-2018").where('price','&gt;=', 70000).where('price','&lt;=', 90000) 查询该集合。

    更通用的替代方法是将产品存储在一个集合中,然后执行 4 次查询以获得您要查找的结果:每个集合中的一个 products-2015products-2016products-2017products-2018

    我建议阅读document on compound queries and their limitations,并观看video on Cloud Firestore queries

    【讨论】:

    • 是的,第一个看起来是最常见的解决方案(根据我之前用谷歌搜索的内容),但它似乎并没有真正的可扩展性。想象一下,您有分页 - 20 个结果/查询(Q1)并且有一个变化,这 20 个都不匹配本地过滤器(Q2),因此您需要重复 Q1 n 次,直到您匹配 Q2 20 次。如果您有 100k 个文档,就有机会发出 100k/20 个请求,这与性能无关。
    • 了解这些性能影响应该会让您很好地了解 Firestore 不支持这些类型的查询的原因。使用 Firestore 提供的性能保证进行大规模查询(获取 20 个结果需要固定的时间,没有多少文档),这意味着它只允许查询可以返回单个范围内的所有结果。
    • 是的,我只是想 100% 确定我没有错过任何好的解决方法:)
    • 如果我们有超过 15 个字段,那么我该如何管理?我需要给你举个例子,但我把代码放在哪里? @FrankvanPuffelen
    • @FrankvanPuffelen 我刚刚从 RTD 切换到 Firestore,我仍然在掌握差异。在 RTD 中,我在两个字段上遇到了相同的过滤范围墙,所以我最终使用了两个不同的查询..我看到Firestore没有什么不同,所以我的情况没有改变,但是对于问题中的问题,像db.collection('products').orderBy('price').startAt('70000').endAt('90000').where('year', '&gt;=', '2015').where('year', '&lt;=', '2018')这样的查询不起作用?按价格排序,将查询限制为所需价格加上过滤另一个参数范围似乎是允许的,对吧?谢谢
    【解决方案2】:

    Flutter中可以做这样的事情,

    final _queryList = await db.collection("products").where('price','>=', 70000).get();
    final _docL1 = _querList.where('price','<=', 90000);
    

    一定会成功的。

    【讨论】:

      【解决方案3】:

      由于here 提到的限制,您不能执行多个范围查询,但是您仍然可以通过像这样对年份进行索引来实现对 UI 的一点成本。

      db.collection("products")
        .where('price','>=', 70000)
        .where('price','<=', 90000)
        .where('yearCategory','IN', ['new', 'old'])
      

      当然,newold 已过时,因此您可以将年份分组为 yearCategory,例如 yr-2014-2017yr-2017-2020 等等。 in 每个查询只能使用 10 个元素,因此这可以让您了解索引年份的范围有多大。

      您可以在插入期间写入yearCategory,或者,如果您的范围很大,例如likes,那么您需要另一个进程来轮询这些数据并更新类别。

      【讨论】:

        猜你喜欢
        • 2019-08-16
        • 2023-03-16
        • 2018-04-10
        • 2020-07-08
        • 2020-03-19
        • 2011-08-30
        相关资源
        最近更新 更多