Firestore - 从文档中获取特定字段

Posted

技术标签:

【中文标题】Firestore - 从文档中获取特定字段【英文标题】:Firestore - get specific fields from document 【发布时间】:2018-09-04 02:56:18 【问题描述】:

我需要什么:

我想在 Firestore 中保存文章或笔记及其各自的字段:

标题 内容(文本或段落) 创建日期 所有者(与其他人分享该文章 以及可以编辑它们的人:https://firebase.google.com/docs/firestore/solutions/role-based-access)

但是当我显示文章列表时,我不需要“内容”字段(以节省带宽)。我已经读过(也许我错了),无法使用 Firestore 进行查询以仅从文档中获取特定字段。

如果是普通的 SQL 从文章中获取特定的列(没有它的内容)它会是这样的:

SELECT title, creation_date, ...
FROM table_name;

所以我选择将两个根级集合的内容分开(为了灵活性和可扩展性)


我目前的结构:

文章收藏:

  - `articles` [collection]
    - `ARTICLE_ID` [document]
      - `creatorId` [field]
      - `title` [field]
      - `date` [field]
      - `owners` [obj field]
          - user1_id: true
          - user2_id: true
          ...

内容集合:

  - `contents` [collection]
    - `ARTICLE_ID` [document]
      - `content` [field]

实时获取文章列表:

firebase.firestore().collection('articles')
  .where(`owners.$user.uid`, '==', true)
  .onSnapshot(querySnapshot => 
    const articles = []
    querySnapshot.forEach((doc) => 
      articles.push(
        id: doc.id,
        ...doc.data()
      )
    )
    // do something with articles array
  )

在另一个视图中显示并获取整篇文章及其内容:

const db = firebase.firestore()
const articleRef = db.collection('articles').doc(articleId)
const contentRef = db.collection('contents').doc(articleId) // same Id as article

articleRef.get().then(articleDoc => 
  if (articleDoc.exists) 
    contentRef.get().then(contentDoc => 
      if (contentDoc.exists) 
        const article = 
          ...articleDoc.data(),
          ...contentDoc.data()
        
        // full article obj
      
    )
   
)

我的问题

您认为最好同时执行两个查询(getArticle 和 getContent)并使用 Promise.all() 等待而不是像我一样嵌套查询?

有没有更好的方法来通过一次查询或更有效地获取文章及其内容?一些提示或想法?

非常感谢您!

【问题讨论】:

你当前的代码有什么问题? @FrankvanPuffelen 我改进了解释。代码正常工作。我对做好事只有存在主义的怀疑。 喜欢评论“存在的怀疑”精彩 【参考方案1】:

Firebase 托管是您处理文章等静态内容的最佳选择。例如,如果您查看AMP-html,它们强烈支持超快速页面加载并突出边缘缓存的好处。 Firebase 托管地址为 advertised to also support global edge caching。

Firestore 和 Firebase 实时数据库是数据库引擎。这些不是提供文章的合适工具。

【讨论】:

谢谢!但这不仅适用于文章。这是为了笔记和其他东西嘿嘿:) 我明白了。原来的问题变了。希望我能够为您节省一些时间。 ...说真的,文章应该是静态的,带有静态 URL。这并不是说某些<aside> 的内容在上完主菜后无法加载。 对不起,也许我用“文章”这个词让你有点困惑。我称之为私人笔记。只有您可以在仪表板中看到带有标题和内容(所见即所得)的笔记。稍后我将添加与其他用户共享它们。不过还是谢谢! =) ? 这实际上是一个巨大的区别。我花了整整一周的时间来思考/弄清楚超快速加载和可索引(搜索/url 驱动)静态内容与数据库驱动(参数化/参数化)Web 应用程序(类似于 AMP-HTML 的荒谬)的重要性。我基本上说的是小心不要过度设计。 KISS 原则... 无论是文章还是笔记,在这里都无关紧要:-)【参考方案2】:

这两种方法都没有比另一种更好。但是有一些关键的区别。

    嵌套读取时,第二次读取仅在第一次读取完成后开始。当您使用Promise.all() 时,两个读取同时开始,因此可以(部分)并行运行。

    另一方面:当您使用Promise.all() 时,您的完成处理程序(您在then() 中运行的代码)在两个文档都加载之前不会执行。如果嵌套调用,则可以在加载第一个文档后更新 UI。

最后,差异可能很小。但由于它们可能对您的用例很重要,因此请衡量结果并查看最适合您的方法。

【讨论】:

在 UI 中,我会显示一个加载图标,直到我从两个查询(文章及其内容)中获得数据为止。因此我认为最好将它们与 Promise.all() 并行使用。我将尝试这两种方法中的哪一种更快/更有效。谢谢! :)【参考方案3】:

根据Firestore Query.select 文档,您应该能够选择所需的字段。

let collectionRef = firestore.collection('col');
let documentRef = collectionRef.doc('doc');

return documentRef.set(x:10, y:5).then(() => 
  return collectionRef.where('x', '>', 5).select('y').get();
).then((res) => 
  console.log(`y is $res.docs[0].get('y').`);
);

【讨论】:

我认为这仅适用于 Google Cloud 和 Node.js 包:P 两个或多个字段有机会吗? @harshadnarkhede 是的,只需用逗号分隔您想要的任何列名的列表。接口是select(...field: (string | FieldPath)[]),所以例如这可以工作:select('field1', 'field2', 'another_field', 'and-a-fourth')【参考方案4】:

为了从 Firestore 文档(版本 9)输出单个字段 - 例如文章集合中的“标题”,您可以使用以下代码 sn-p:

const q = query(collection(db, 'articles'))
let results = [];
await getDocs(q);
results = getLocation.docs.map((doc) => doc.data()['title']);
results.sort()

结果数组将仅包含标题字段,按字母顺序排序 (请注意,您必须引用 Firestore 数据库并从 Firestore 导入“getDocs”、“query”和“collection”模块)

【讨论】:

以上是关于Firestore - 从文档中获取特定字段的主要内容,如果未能解决你的问题,请参考以下文章

获取具有等于flutter中特定字符串的字段的Firestore文档

使用 Swift (Firestore) 访问特定文档字段

如何从flutter中的firestore文档字段中获取数据?

如何在 Swift 中从 Cloud FireStore Firebase 访问特定字段

Swift - 从随机创建的文档 ID 中获取字段(Firestore)

Flutter:使用 Streambuilder<QuerySnapshot> 时如何在 firestore 中获取特定文档