Firestore查询,其中结果包含一个字段,该字段包含要传递给第二个查询以检索所有文档的文档引用。

4 浏览
0 Comments

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}));
});

非常感谢任何帮助。

0
0 Comments

问题:如何在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的文档了解更多信息。

希望对你有所帮助!

0