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

Bla*_*ode 15 javascript firebase google-cloud-firestore

我需要的:

我想在Firestore中使用各自的字段保存文章或注释:

但是,当我显示文章列表时,我不需要"内容"字段(以节省带宽).我已经读过(也许我错了),不可能通过Firestore查询文档中的特定字段.

如果从文章中获取特定列(没有其内容)是正常的SQL,它将类似于:

SELECT title, creation_date, ...
FROM table_name;
Run Code Online (Sandbox Code Playgroud)

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


我目前的结构:

文章集:

  - `articles` [collection]
    - `ARTICLE_ID` [document]
      - `creatorId` [field]
      - `title` [field]
      - `date` [field]
      - `owners` [obj field]
          - {user1_id}: true
          - {user2_id}: true
          ...
Run Code Online (Sandbox Code Playgroud)

内容集合:

  - `contents` [collection]
    - `{ARTICLE_ID}` [document]
      - `content` [field]
Run Code Online (Sandbox Code Playgroud)

要实时获取文章列表:

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
  })
Run Code Online (Sandbox Code Playgroud)

要在另一个视图中显示并获得整篇文章的内容:

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
      }
    })
  } 
})
Run Code Online (Sandbox Code Playgroud)

我的问题

  • 你认为最好同时做两个查询(getArticle和getContent)并等待Promise.all()而不是像我那样嵌套查询吗?

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

非常感谢你提前!

abr*_*ham 20

根据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')}.`);
});
Run Code Online (Sandbox Code Playgroud)

  • 我认为这仅适用于 Google Cloud 和 Node.js 包:P (13认同)
  • @harshadnarkhede 是的,只需用逗号分隔您想要的任何列名称的列表。接口是`select(...field: (string | FieldPath)[])`,所以例如这可以工作:`select('field1', 'field2', 'another_field', 'and-a-fourth' )`。 (2认同)

Fra*_*len 6

两种方法都没有比另一种更好。但是有一些关键差异。

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

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

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