Firestore:按文档数组中的项目查询

Posted

技术标签:

【中文标题】Firestore:按文档数组中的项目查询【英文标题】:Firestore: Query by item in array of document 【发布时间】:2018-04-01 15:10:40 【问题描述】:

我有 2 个集合 "photos""users" 并且 "users" 中的每个文档都有一张或多张照片带有数组的 ID

photos > 5528c46b > name: "Photo1"
         a1e820eb > name: "Photo2"
         32d410a7 > name: "Photo3"
users > acd02b1d > name: "John", photos: ["5528c46b"]
        67f60ad3 > name: "Tom", photos: ["5528c46b", "32d410a7"]
        7332ec75 > name: "Sara", photos: ["a1e820eb"]
        9f4edcc1 > name: "Anna", photos: ["32d410a7"]

我想要拥有一个或多个特定照片 ID 的所有用户

有没有办法做到这一点?

【问题讨论】:

【参考方案1】:

请参阅Henry's answer,因为我们没有提供可用的 Array Contains 查询。

很遗憾,目前还没有,虽然它在我们的路线图上。

与此同时,您需要改用地图,其形式为:

photos: 
    id1: true
    id2: true

现在您可以通过 photos.id1 == true 过滤找到所有 id1 的用户。

在Firebase documentation 中了解有关查询此类集合的更多信息。

【讨论】:

此路线图是否已在某处发布?只是好奇。 @DanMcGrath 此功能/路线图是否有任何更新? Firestore 不允许我在没有索引每个可能的 ID 的情况下以这种方式查询数据。有什么方法不需要索引,或者有一个动态索引? @KevinBeal 提到的最大问题是,如果您需要复合查询,您可以索引键。对于任何高级查询功能来说,这都是一个非常大的问题。 @Dan McGrath 确实如此,但仅限于一个参数。你可以做.where('photos', 'array-contains', 'id1'),但你不能.where('photos', 'array-contains', ['id1', 'id2'])【参考方案2】:

这里对答案进行了一些扩展,因为有些人似乎对必须为每个键创建索引感到困惑,Firestore 已经为您的数据编制了简单查询的索引,因此您可以执行类似

的简单查询
documentReference.where('param','==','value').onSnapshot(...)

但您不能进行复合查询,除非您为这些参数的数据编制索引。所以你需要索引才能做这样的事情:

 documentReference.where('param','==','value').where(..otherparams...).onSnapshot(...)

所以只要你需要照片作为 id 就可以保存为

usersCollection :                        (a collection)
    uidA:                                (a document)
         photoField:                     (a field value that is a map or object)
            fieldID1 : true              (a property of the photoField)
            fieldID2 : true              (a property of the photoField)
            etc ...  

并且您可以简单地查询在他们的 photoField 中具有 fieldID1 的用户,而无需形成任何索引以及下面的类似查询。

firestore.doc('usersCollection/uidA').where('photoField.fieldID1','==',true).onSnapshot(...)

【讨论】:

【参考方案3】:

添加了 'array-contains' 查询运算符,用于与 .where() 一起查找数组字段包含特定元素的文档。

https://firebase.google.com/support/release-notes/js5.3.0

更新:也可以在@google-cloud/firestore:https://github.com/googleapis/nodejs-firestore/releases/tag/v0.16.0

更新 2 https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.html

Update 3 现已在 Admin Node.js SDK v6.0.0 https://github.com/firebase/firebase-admin-node/releases

中提供

【讨论】:

Welp 花了一段时间 :D 我正在做一个我需要这个的项目,我很高兴我落后到足以让 firebase 团队领先:p 不幸的是,没有办法用很少的“数组包含”值进行查询。 @BohdanDidukh 你试过链接他们吗? .where(..).where(...)? @Henry,是的,我试过了。 Firebase 服务器以错误响应我:FirebaseError:无效查询。查询仅支持单个数组包含过滤器。 是否可以使用对象键的值来查询对象数组,例如 arrayItems:[id:123, ...., id: 234, ...]...并做类似 .where('arrayItems', 'array-contains', 'id=123')?该语法似乎不起作用,但我仍然希望有一种方法可以做类似的事情。请指教【参考方案4】:

截至 2019 年 11 月,Firestore 现在添加了一个“in”查询。 根据the announcement article:

使用 in 查询,您可以查询特定字段的多个值 (最多 10 个)在单个查询中。您可以通过传递一个包含 您要搜索的所有值,Cloud Firestore 将匹配 其字段等于这些值之一的任何文档。

【讨论】:

【参考方案5】:

使用 Firebase 版本 9(2021 年 12 月更新):

您可以在 "while()" 中使用 "array-contains"一个照片文档 ID 来获取 所有拥有它的用户

import 
  query,
  collection,
  where,
  getDocs
 from "firebase/firestore";

// Here
const q = query(
  collection(db, "users"),
  where("photos", "array-contains", "5528c46b")
);
// Here

const usersDocsSnap = await getDocs(q);

usersDocsSnap .forEach((doc) => 
  console.log(doc.data()); // "John's doc", "Tom's doc"
);

您还可以在 "while()" 中将 "array-contains-any"一个或多个带有数组的照片文档 ID 结合使用 strong> 获取更多对应用户

import 
  query,
  collection,
  where,
  getDocs
 from "firebase/firestore";

// Here
const q = query(
  collection(db, "users"),
  where("photos", "array-contains-any", ["5528c46b", "a1e820eb"])
);
// Here

const usersDocsSnap = await getDocs(q);

usersDocsSnap .forEach((doc) => 
  console.log(doc.data()); // "John's doc", "Tom's doc", "Sara's doc"
);

【讨论】:

以上是关于Firestore:按文档数组中的项目查询的主要内容,如果未能解决你的问题,请参考以下文章

获取值不在数组中的 Firestore 文档

获取值不在数组中的 Firestore 文档

Flutter:按时间戳查询 Firestore 文档

从 id 数组中获取 firestore 文档列表

Firestore 更新数组字段中的单个项目

按对象键的Firestore查询