【问题标题】:Firestore query with subcollection带有子集合的 Firestore 查询
【发布时间】:2017-12-28 08:01:49
【问题描述】:

这是对 Firebase 的限制,还是我做错了?一切正常,直到我在代码中间添加db.collection('users').doc(friendId).get()...。提前致谢。

const db = admin.firestore();
const friendRef = db.collection('users').doc(id).collection('friends');

friendsList = [];

friendRef.get().then((onSnapshot) => {
    if (!onSnapshot.empty) {
        onSnapshot.forEach((friend) => {

            const friendId = String(friend.data().person_id);

            db.collection('users').doc(friendId).get().then((result) => {
                const firstName = String(result.data().name.first);
                const lastName = String(result.data().name.last);
            })

            const data = {
                personId: friendId,
                firstName: firstName,
                lastName: lastName,
            }

            friendsList.push(data);
        })

        res.send(friendsList);
    } else {
        res.send({
            'message': 'no friends'
        });
    }
}).catch((e) => {
    res.send({
        'error': e
    });
})

【问题讨论】:

    标签: javascript firebase google-cloud-functions google-cloud-firestore


    【解决方案1】:

    数据从 Firestore 异步加载。这意味着当您将响应发送回客户端时,尚未从 Firestore 加载数据。

    查看这一点的最简单方法是使用一些放置良好的日志语句:

    console.log("Before getting friend");
    db.collection('users').doc(friendId).get().then((result) => {
      console.log("Got friend");
    })
    console.log("After getting friend");
    

    当你只运行这段代码时,它会打印:

    交朋友之前

    交朋友后

    有朋友

    这可能不是您期望的日志顺序。原因是数据可能需要一些时间才能从 Firestore 中返回。因此,它不会阻塞线程,而是继续运行线程,然后在数据可用时调用您的回调函数。不幸的是,这意味着您的 res.send(friendsList) 最终会向客户端发送一个空列表,因为数据尚未加载。

    解决这个问题的方法是使用一堆嵌套回调,使用Promise.all(),或者ES6 的新async/await 关键字。使用 Promise,代码如下所示:

    const db = admin.firestore();
    const friendRef = db.collection('users').doc(id).collection('friends');
    
    friendRef.get().then((onSnapshot) => {
      var promises = [];
    
      onSnapshot.forEach((friend) => {
        const friendId = String(friend.data().person_id);    
        promises.push(db.collection('users').doc(friendId).get());
      });
    
      Promise.all(promises).then((snapshots) => {
        friendsList = [];
        snapshots.forEach((result) => {
          friendsList.push({
            personId: result.id,
            firstName: result.data().name.first,
            lastName: result.data().name.last,
          });
        });
        res.send(friendsList);
      });
    }).catch((e) => {
      res.send({
        'error': e
      });
    })
    

    因此,我们首先构建所有好友读取操作的列表,然后在所有这些操作完成后,我们构建响应并将其发回。

    【讨论】:

    • 太棒了,它奏效了。我现在明白了你的解释。再次感谢。我很想为此使用 ES6。如果你有时间并且不介意,你可以使用 ES6 async/await 发送它,这样我就知道了。我将开始使用 Google Functions 学习 ES6。提前致谢。
    • 嗨弗兰克。一切正常,除了由于某种原因我没有得到personId: snapshot.id 的输出。我尝试了一些方法:snapshots.idresult.id,但这也没有用。这是onSnapshot.forEach((friend)... 的ID,应该是friend.id。再次感谢。
    • 您的代码没有显示您如何初始化friendId,所以我假设它是文档 ID:firebase.google.com/docs/reference/js/…。如果不是这种情况,您需要修改解决方案的该部分以满足您的需求。
    • 再次感谢@FrankvanPuffelen 的帮助。我仍然不知道如何将文档 ID 从 Friends 集合推送到 FriendsList 数组。我问了一个新问题,因为我认为可能很难在评论中解释它。 firestore-with-promises-and-push.
    • 啊...应该是result.id,我刚刚更新了代码。 result.id 是您加载的文档的 ID。并且由于您基于friendId 加载文档,因此它将与friendId 的值相同。
    猜你喜欢
    • 2020-12-18
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    相关资源
    最近更新 更多