【问题标题】:Firebase query by document id PLUS property valueFirebase 按文档 ID PLUS 属性值查询
【发布时间】:2020-11-19 19:26:38
【问题描述】:

我对 Firebase 完全陌生,也许我无法搜索到正确的关键字,但这是我想做的:

我想通过 id 从数据库中读取文档,但前提是该文档具有特定的属性集。更具体地说,这就像一个小型博客服务器,我想在其中读取帖子的数据,但前提是它的“已发布”属性设置为 true。我不希望未发布的帖子最终出现在客户端。

我正在使用 JavaScript SDK,但只能通过 ID 或属性找到查找示例...

这可能吗?


更新: 我现在拥有的是(这是 Firestore):

firebase.firestore().collection('blog-posts').doc(id).get()

然后在客户端检查属性:

if (data && data.published === "true")

我希望所有过滤都发生在服务器端。

【问题讨论】:

  • Firestore 还是实时数据库?您可以发布您当前正在使用的相关代码吗?以下是在 Firestore 中进行复合查询的方法:firebase.google.com/docs/firestore/query-data/…
  • “我不希望未发布的帖子最终出现在客户端。”虽然 Doug 的回答为您提供了编写查询的解决方案,但请注意,用户很容易通过删除第二个 where 子句来阅读未发布的帖子。换句话说,如果您希望未发布的文档“无法找到”(而不仅仅是被查询过滤掉),您应该在查询的同时使用安全规则。

标签: javascript firebase google-cloud-firestore


【解决方案1】:

如果您只想在字段具有特定值时获取文档,您将无法在其 DocumentReference 上使用 get()。您必须使用文档 ID 和字段作为该查询的过滤器,使用 FieldPath.documentId() 对集合执行查询:

const qsnap = await firebase.firestore()
    .collection('blog-posts')
    .where(firebase.firestore.FieldPath.documentId(), "==", id)
    .where("published", "==" true)
    .get()

这会产生一个 QuerySnapshot,您必须检查是否提供了文档。

if (qsnap.docs.length > 0) {
    const doc = qsnap.docs[0];
}

请注意,即使未返回文档,执行此查询仍需要读取 1 个文档。

【讨论】:

  • 哦,哇,这开箱即用。谢谢,这对我来说符合所有条件!
  • 使用此响应时要非常小心 - 以这种方式使用的 FieldPath.documentId() 仅适用于顶级集合。它实际上不返回 documentId;它返回文档的完整路径,包括所有更高级别的集合和文档。请参阅下面的答案。
【解决方案2】:

您可以使用where 函数在服务器端过滤数据。

firebase.firestore().collection('blog-posts').where('published', '==', 'true').where(firebase.firestore.FieldPath.documentId(), '==', id).get()

【讨论】:

  • 不幸的是,我需要通过其 ID 阅读一篇特定的帖子。 (当有人猜测文档 ID 时,我不希望帖子可读)
【解决方案3】:

Firestore 不会轻易让您过滤/选择 documentID;除其他问题外,FieldPath.documentId() 返回文档的完整路径,而不仅仅是 id;请参阅此问题/答案,以获得对正在发生的事情的相当冗长的解释:

Firestore collection group query on documentId

可以将Id复制到文档中的一个字段中,并通过它进行查询(我的Firestore包装器会自动帮助解决这个问题)-但是- 这很快变成了我所见过的所谓“X-Y”问题 - 问“我如何做 Y?”只是因为你已经假设它是“我该如何做 X?”的答案

问题是为什么要通过文档ID查询?此 ID 是否是其他一些信息的代理(例如识别用户的方式)?如果是这样,请使用用户 ID 作为字段。通常,documentId 更多的是关于 Google Firestore 有效地对数据库进行分片以提高性能,而不是作为真正的标识符。由于 documentId 被认为是唯一的(或者,正如所引用的答案所解释的,文档的完整路径是唯一的),因此它通常不太适合查找。

打个比方:使用 documentId 查找文档就像使用市政包裹号来指定地址一样。当然,它是独一无二的,但“Division 46675 Tract 32567 Parcel 12344”的用处很多不如“450 Lazy Deer Road, Winnetka, New Jersey”。

所以:在你的情况下,问问你自己:你从哪里获得了 documentId?它代表什么?我可以将 那个 存储在我的文档中,以便我可以使用复合查询吗?

firebase.firestore().collection('blog-posts').where([whatever query identifies the document or documents]).where('published', '==', 'true').get()

注意您的第一个条件是识别一个还是识别多个文档,响应对象将包含一个 ARRAY,其中可能包含一个或多个文档。

对 Firestore 和其他 NoSQL 数据库的最佳一般建议是花时间准确地确定如何您希望使用您的数据(即您的查询)并构建您的结构让更容易。请记住,Firestore 应该是让您的生活更轻松的工具,而不是让成为 Firestore 的奴隶。

【讨论】:

    猜你喜欢
    • 2022-12-05
    • 2018-07-06
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多