Firebase Firestore-使用多个“包含数组”过滤数据

时间:2019-06-11 13:06:01

标签: javascript firebase google-cloud-firestore

我正在努力寻找有关使用Firebase Firestore过滤数据的最佳实践的良好材料。我想根据用户选择的类别过滤数据。我在Firestore数据库中存储了一组文档,并且每个文档都有一个数组,其中包含该单个文档的所有适当类别。为了进行过滤,我还要保留一个用户首选类别的本地数组。我要做的就是根据用户的首选类别过滤数据。

MgntUtils Github link

考虑我将用户的首选类别存储为字符串数组([“ Film”,“ Music”])。我正计划使用firestore的“ array-contains”方法,例如

db.collection(collectioname)
.where('categoriesArray', 'array-contains', ["Film", "Music"])

后来我发现我不能对数组本身使用'array-contains',在研究了这个问题之后,我决定按照firestore categories field的方式更改数据结构。

here

一旦将类别从数组更改为映射,我以为可以使用多个条件过滤文档

let query = db.collection(collectionName)
      .where(somefield, '==', true)

this.props.data.filterCategories.forEach((val) => {
  query = query.where(`categories.${val}`, '==', true);
});

query = query
        .orderBy(someOtherField, "desc")
        .limit(itemsPerPage)

const snapshot = await query.get()

现在问题2,firebase需要为复合查询添加索引。我在每个文档中保存的类别是动态的,无法提前添加这些索引。在这种情况下,理想的解决方案是什么?任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:2)

这是2019年11月7日推出的Firebase JavaScript SDK的新功能:

array-contains-any运算符可将同一字段上的最多10个包含数组的子句与一个逻辑或组合。一个包含数组的查询将返回文档,其中给定字段是一个包含一个或多个以下内容的数组比较值”

citiesRef.where('regions', 'array-contains-any',
    ['west_coast', 'east_coast']);

答案 1 :(得分:0)

您是否打算检索具有确切类别数组的文档?假设您的用户偏好设置为["Film", "Music"]。您是否只想检索带有电影或音乐的文档,还是只希望检索带有电影或音乐的文档?

如果是后者,那么也许您可以使用“电影”查询所有文档,然后使用“音乐”查询所有文档,然后将其合并。但是,这里的缺点是在categoryArray字段中同时具有“电影”和“音乐”的情况下,读取了一些多余的文档。

您还可以使用Algolia探索以启用全文本搜索。在这种情况下,您可能会将类别列表存储为一个字符串,并用逗号分隔,然后在用户更改其首选项时更新整个字符串。

对于前一种情况,除了可能按字母顺序将其存储为连接字符串之外,我没有遇到任何可行的解决方案?其他人可能有比我更坚实的解决方案。

希望这会有所帮助!

答案 2 :(得分:0)

每个迭代都应该是自己独立的查询,而不是遍历要查询的每个类别并将子句附加到单个query对象上。您可以将类别保留在数组中。

<document>
    - itemId: abc123
    - categories: [film, music, television]

如果您希望执行OR查询,则将创建n循环,其中每个循环将查询数组包含该类别的文档。然后,最后,您将根据项目的标识符从结果中删除(删除重复项)。因此,如果您想查询电影或音乐,则将执行两个循环,其中第一个迭代查询数组中包含电影的文档,第二个循环查询文档中包含数组的音乐。结果将被放入同一集合中,然后您只需删除所有具有相同itemId的重复项即可。

因为categories是一个静态字段,所以复合索引限制也没有问题。真正的问题与分页有关,因为您可能需要保留所有提取的itemId的记录,以防将来的结果页返回已提取的项目,这将创建O(N ^ 2)场景(更多采用big-o表示法:https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/)。并且由于您是在本地进行重复数据删除,因此无法保证用户看到的分页块均匀。例如,如果将每个分页块设置为25个文档,则取决于从每个块中删除了多少重复项,某些页面可能最终显示24个页面,一些页面显示21个页面,其他页面显示14个页面。

答案 3 :(得分:0)

您的查询包含orderBy子句。结合任何相等性过滤器,这要求您创建一个索引来支持该查询。无法避免这种情况。

如果删除orderBy,则可以使用文档中的map属性使用灵活,动态的过滤器来实现相等性。这是无需创建索引就能拥有动态过滤器的唯一方法。当然,这意味着您将必须在客户端上对查询结果进行排序和分页。