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

我需要什么:

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

但是当我显示文章列表时,我不需要“内容”字段(以节省带宽)。我已经读过(也许我错了),无法使用 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 我改进了解释。代码正常工作。我对做好事只有存在主义的怀疑。
  • 喜欢评论“存在的怀疑”精彩

标签: javascript firebase google-cloud-firestore


【解决方案1】:

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

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

【讨论】:

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

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

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

  2. 另一方面:当您使用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”模块)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-13
    • 2019-05-28
    • 2019-02-26
    • 2020-08-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    相关资源
    最近更新 更多