Firestore查询,其中结果包含一个字段,该字段包含要传递给第二个查询以检索所有文档的文档引用。
Firestore查询,其中结果包含一个字段,该字段包含要传递给第二个查询以检索所有文档的文档引用。
我有一个数据库结构,试图处理经典的事件/参与者模式。我有参与者的事件,并且参与者参加事件。
我认为,为了正确扩展查询参与者参加的所有事件的详细信息,不应该查询所有事件然后过滤它们以找到一个参与者,这样做是不好的做法。对于这个观点,欢迎提出评论。用户在一个集合中,事件在另一个集合中。所以我在用户中添加了一个subEvent子集合,用于存储他们参与的事件的文档引用。现在我想从用户的查询中检索这些文档引用,并在事件的第二次查询中检索详细的事件记录。下面是包含两者事件ID的模式。
(图片链接)
我的第一个查询看起来像这样:
const asnapshot = await db.collection("users").doc(_req.params.id).collection("subEvents").get();
第二个查询是:
const doc = await db.collection("events").doc(results_from_asnapshot).get();
其中results_from_asnapshot只是第一个查询中的文档ID的占位符。请注意,第一个查询将返回多个结果,而第二个查询只返回一个结果。为了处理这个问题,我试图从快照中创建一个包含所有事件的结果,然后在第二个查询中循环遍历它们,以建立参与者参加的所有事件的完整详细列表。
出现了几个问题,我希望得到帮助。一个问题是第一个查询的输出在第二个查询中是否可接受,似乎对于什么能够工作有不同的答案。有些人说像这样的字符串将起作用,而其他人则不行。在一个测试查询中,我遇到了“doc.data() is not a function”错误,直到无缘无故地消失。
const doc = await db.collection("events").doc("0adFOpcHZZONGDu3Qw7n").get();
其次,如何正确循环第二个查询。第三个问题是为什么第二个查询,在await之前,会警告linter将忽略await。我知道一个查询必须在下一个查询开始之前结束,那为什么不使用await呢?
下面是我极其有缺陷的尝试之一,你可以注意到它是一个node.js的firebase函数:
const functions = require("firebase-functions"); const express = require("express"); const admin = require("firebase-admin"); admin.initializeApp(); const appWhen = express(); const db = admin.firestore(); appWhen.get("/eventsDetails/:id", async (_req, res) => { functions.logger.log("Function started"); const snapshot = await db.collection("users").doc(_req.params.id).collection("subEvents").get(); const userevents = []; snapshot.forEach((doc) => { const id = doc.id; const data = doc.data().eventID; userevents.push({id, ...data}); }); functions.logger.log("userevents", JSON.stringify(userevents)); const eventlist = []; userevents.forEach((event) => { const doc = db.collection("events").doc(event).get(); const id = doc.id; const eventData = doc.data(); functions.logger.log("eventData", eventData); eventlist.push({id, ...eventData}); }); res.status(200).send(JSON.stringify({id: id, ...eventlist})); });
非常感谢任何帮助。
问题:如何在Firestore查询中,查询结果包含一个字段,该字段包含一个文档引用,然后将该引用传递给第二个查询以检索所有文档?
原因:代码存在一些问题,需要进行修正。首先,使用forEach循环无法按顺序读取文档,应该使用现代的for ... of循环,并在其中使用await。其次,如果你正在使用查询结果中的引用字段,只需要执行引用并获取数据即可。最后,代码中的res.status(200).send(JSON.stringify({id: id, ...eventlist}));行存在问题,无法获取变量id的值。
解决方法:根据修正后的代码示例,可以按照以下步骤进行修正。首先,使用for ... of循环遍历userevents数组,使用await获取引用字段对应的文档数据。然后,将文档数据添加到eventlist数组中。最后,发送响应时,根据具体情况确定要使用的id值。
修正后的代码示例如下:
const functions = require("firebase-functions"); const express = require("express"); const admin = require("firebase-admin"); admin.initializeApp(); const appWhen = express(); const db = admin.firestore(); appWhen.get("/eventsDetails/:id", async (_req, res) => { functions.logger.log("Function started"); const snapshot = await db.collection("users").doc(_req.params.id).collection("subEvents").get(); const userevents = []; snapshot.forEach((doc) => { const id = doc.id; const eventID = doc.data().eventID; userevents.push({id, eventID}); }); functions.logger.log("userevents", JSON.stringify(userevents)); const eventlist = []; for (const event of userevents) { if (event.eventID) { const doc = await event.eventID.get(); if (doc.exists) { const id = doc.id; const eventData = doc.data(); eventlist.push({id, ...eventData}); } else { console.log("No such document!"); } } else { // .. Do something } } res.status(200).send(JSON.stringify({id: ??, ...eventlist})); });
当查询结果包含引用类型字段时,该字段将作为DocumentReference类型对象显示在DocumentSnapshot中。可以像对待自己构建的任何其他DocumentReference一样处理它。可以调用get()方法获取引用的文档数据。不需要执行任何操作来解析文档的路径(除非你想要这样做)。这是使用引用类型的一个优点,而不是将其存储为字符串类型字段,因为你将再次构建一个新的查询来获取文档。可以查阅Firestore DocumentReference的文档了解更多信息。
希望对你有所帮助!