【问题标题】:Get the first document from Firestore subcollection with primary document?从 Firestore 子集合中获取第一个文档和主文档?
【发布时间】:2021-09-11 11:22:26
【问题描述】:

我正在使用 Node.js(我很新)和 Google Cloud Firestore 数据库来保存文档,根据:

  • 用户
  • 推文

一个用户文档,即一个用户,在子集合“推文”中有许多推文。我有兴趣将用户连同子集合中的最后一条推文一起检索,所以我得到了一个这样的 JSON 文件。换句话说,这就是我想要得到的

users: {
    {
    name:'john',
    twitter_username:'johnny',
    tweets: {
    text: "I am called johnny, this is my tweet",
    created_at: "2021-06-29 12:00:00"
    },
    },
    {
    name:'anne',
    twitter_username:'anne',
    tweets: {
    text: "I am called anne, this is another tweet",
    created_at: "2019-06-28 12:00:00"
    },
    }
}

我有这个功能:

   function getUserData() {
       return db.collection('users').get()
            .then((querySnapshot) => {
                var docs = querySnapshot.docs.map(doc => [doc.data(), doc.id]);         
                //console.log(docs);
                return docs

如果我可以用最后一条推文获取并替换 doc.id(即用户文档 ID),我想会解决它。但是我该怎么做呢?

任何其他解决方案(可能带有 for 循环)也可以。我在这个看似简单的问题上花了几个小时,但无法让它同时返回用户数据和推文数据。

编辑 2:

我意识到我可以做到这一点:

function getUserData() {
   return db.collection('users').get()
        .then((querySnapshot) => {
            var docs = querySnapshot.docs.map(doc => [doc.data(), doc.id, getStuff(doc.id)])
            console.log(docs)
            return docs                          
        });
}

function getStuff(doc_id) {
   return db.collection('users').doc(doc_id).collection('tweets').limit(1).get()
        .then((querySnapshot) => {
            var docs = querySnapshot.docs.map(doc => doc.data());         
            console.log("TWEETS", doc_id, docs[0]['text']);
            return docs[0]['text']
        });   
}

产生的日志结果为:

TWEETS DAU86mxIhmD6qQQpH4F God’s country!
TWEETS JQHTO0jUjAodMQMR6wI I’m almost there Danny! 

来自 getStuff 函数。

现在唯一的问题是我无法让 map 函数等待 getStuff,所以 return docsgetStuff(doc.id) 返回一个 Promise { <pending> }

我不熟悉 Promises 和 await/async,我无法让它工作。解决这个 Promise pending -> twitter text 将解决我的问题。我该怎么做?

【问题讨论】:

    标签: node.js google-cloud-firestore


    【解决方案1】:

    如果你想获取单个用户的数据,你可以这样写代码:

    const getUserData = async (userUid) => {
      const userSnap = await db.collection("users").doc(userUid).get();
      const tweetSnaps = await db
        .collection("tweets")
        .orderBy("created_at", "desc")
        .limit(1)
        .get();
    
      let tweet = {};
    
      tweetSnaps.forEach((doc) => {
        tweet = doc.data();
      });
    
      return {
        ...userSnap.data(),
        ...tweet,
      };
    };
    
    

    我们首先获取用户,然后查询最后一条推文并获取它。我们按created_attweets 集合进行排序,并将其限制为单个文档。

    如果您想一次为所有用户获取相同的数据,我们需要稍微更改代码,但逻辑是相同的。

    如果数据保存在单独的集合中,则无法在单个数据库请求中获取它们。

    编辑 2 的更新

    这里你的代码应该是正确的async/await

    const getUserData = async () => {
      const querySnapshot = await db.collection("users").get();
    
      const docs = querySnapshot.docs;
    
      for (let i = 0; i < docs.length; i++) {
        const element = docs[i];
        doc.data(),
        doc.id,
        await getStuff(doc.id),
      }
    
      console.log(docs);
      return docs;
    };
    
    const getStuff = async (doc_id) => {
      const querySnapshot = await db
        .collection("users")
        .doc(doc_id)
        .collection("tweets")
        .limit(1)
        .get();
    
      var docs = querySnapshot.docs.map((doc) => doc.data());
      console.log("TWEETS", doc_id, docs[0]["text"]);
      return docs[0]["text"];
    };
    
    

    【讨论】:

    • 我已经用部分解决方案更新了我的问题,将此问题呈现为更多与异步/承诺相关的问题。如果您对此有任何想法,请不吝赐教。
    • 啊,我明白了。您的问题是 map 不支持 async 呼叫。您只需要将数据存储到一个数组中并使用for 循环。然后你可以使用async/await。我会更新你的代码。
    猜你喜欢
    • 2019-11-13
    • 2023-03-18
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 2018-04-04
    • 1970-01-01
    相关资源
    最近更新 更多