在云函数中,我如何从另一个集合加入以获取数据?

问题描述 投票:0回答:4

我正在使用云功能向移动设备发送通知。我在 Firestore

clientDetail
clientPersonalDetail
中有两个集合。我在两个集合中都有
clientID
相同,但日期存储在
clientDetail
中,名称存储在 clientPersonal 中。

看一下:

ClientDetail -- startDate
             -- clientID
             .......

ClientPersonalDetail -- name
                     -- clientID
                     .........

这是我的完整代码:

exports.sendDailyNotifications = functions.https.onRequest(  (request, response) => {
var getApplicants = getApplicantList();
console.log('getApplicants', getApplicants);

cors(request, response, () => {
  admin
    .firestore()
    .collection("clientDetails")
    //.where("clientID", "==", "wOqkjYYz3t7qQzHJ1kgu")
    .get()
    .then(querySnapshot => {
      const promises = [];
      querySnapshot.forEach(doc => {
        let clientObject = {};
        clientObject.clientID = doc.data().clientID;
        clientObject.monthlyInstallment = doc.data().monthlyInstallment;
        promises.push(clientObject);
      });

      return Promise.all(promises);
    }) //below code for notification
    .then(results => {
      response.send(results);
      results.forEach(user => {
        //sendNotification(user);
      });
      return "";
    })
    .catch(error => {
      console.log(error);
      response.status(500).send(error);
    });
});

} );

上面的函数显示了一个像这样的对象

{clienId:xxxxxxxxx, startDate:23/1/2019}

但是我需要在通知中显示 ClientID 而不是名称,因此我必须加入 clientPersonal 集合才能使用 clientID 获取名称。 应该做什么?

如何创建另一个函数,通过传递 clientID 作为参数来仅返回 name ,并等待它返回 name 。 有人可以帮忙吗?

node.js firebase push-notification google-cloud-firestore google-cloud-functions
4个回答
4
投票

但是我需要在通知中显示 ClientID 而不是名称,因此我必须加入 clientPersonal 集合才能使用 clientID 获取名称。应该做什么?

不幸的是,Firestore 中没有 JOIN 子句。 Firestore 中的查询很浅薄。这意味着它们仅从运行查询的集合中获取项目。无法在单个查询中从两个顶级集合中获取文档。 Firestore 不支持一次性跨不同集合进行查询。单个查询只能使用单个集合中文档的属性。

如何创建另一个函数,通过传递 clientID 作为参数来仅返回名称,并等待它返回名称。

所以我能想到的最简单的解决方案是首先查询数据库以获得

clientID
。获得此 id 后,再进行一次数据库调用(在回调内),这样您就可以获得相应的名称。

另一个解决方案是将用户名添加为

ClientDetail
下的新属性,这样您只能查询数据库一次。这种做法称为
denormalization
,是 Firebase 中的常见做法。如果您是 NoQSL 数据库的新手,我建议您观看此视频,Firebase 数据库中的非规范化是正常的,以便更好地理解。它适用于 Firebase 实时数据库,但相同的规则适用于 Cloud Firestore。

此外,当您复制数据时,需要记住一件事。就像添加数据一样,您也需要维护它。换句话说,如果你想更新/删除一个项目,你需要在它存在的每个地方都进行操作。


2
投票

“更简单”的解决方案可能是复制数据。这在 NoSQL 世界中很常见。

更准确地说,您可以在

ClientDetail
集合中的文档中添加客户的价值
name


1
投票

此时您可以使用两个额外的函数来使您的代码清晰。一个函数将从集合

ClientDetail
中读取所有文档,而不是获取所有字段,而只会获取
ClientID
。然后调用另一个函数,该函数将扫描集合中的所有文档
ClientPersonalDetail
,并仅检索具有 ClientID 的部分。比较这两者是否匹配,然后在匹配时执行任何操作。

您可以参考Cloud Firestore 入门文档,了解如何从 Firestore 创建、添加和加载文档。

你的

package,json
应该看起来像这样:

{
  "name": "sample-http",
  "version": "0.0.1",
  "dependencies": {
    "firebase-admin": "^6.5.1"
  }
}

我自己编写了一些代码,这是我的 GitHub 中的示例代码。通过部署此功能,将扫描一个集合中的所有文档,并比较另一集合中文档的 ClientID。当它找到匹配时,它将记录一条消息,否则它将记录一条 ID 不匹配的消息。您可以利用该函数如何运行的想法并在您的代码中使用它。


0
投票

您可以使用 Promise.all 方法,该方法在所有承诺都已履行时返回一个承诺。而这个最终的承诺将拥有您想要的所有藏品。

这是 Express 上的 firestore 功能的示例

app.get("/endpoint/:id", async (request, response) => {
    const id = request.params.id
    const collectionSnapshot = await 
      db.collection(collection).doc(id).get()
    const [collection] = await Promise.all([
      async () => {
        const collectionData = collectionSnapshot.data()
        const subCollectionSnapshot = await db
         .collection(subCollection)
         .where("collection_id", "==", collectionData.id)
         .get()
      return {
        ...collection,
        subCollection,
    }
  },
])

const collectionData = await collection()

// Send collection and subCollection data to the client
response.status(200).send({ data: { ...collectionData } })

})

© www.soinside.com 2019 - 2024. All rights reserved.