如何将具有动态 ID 的文档保存到 Cloud Firestore?总是在变化

Posted

技术标签:

【中文标题】如何将具有动态 ID 的文档保存到 Cloud Firestore?总是在变化【英文标题】:How to save a document with a dynamic id into Cloud Firestore? Always changing 【发布时间】:2020-01-22 10:27:46 【问题描述】:

我使用 Cloud Firestore 作为我的数据库 这是我网页上的表单代码,它在我的 Cloud Firestore 集合中创建了一个名为“esequiz”的新文档。那么我如何对其进行编码,使其始终将数据库中的文档数量加 1?并且还对数据库中的文档数量进行了限制

form.addEventListener('submit', (e) => 
e.preventDefault();
db.collection('esequiz').add(
    question: form.question.value,
    right: form.right.value,
    wrong: form.wrong.value
);
form.question.value = '';
form.right.value = '';
form.wrong.value = '';
);

目前可以使用,但会显示为自动生成的 ID。我如何让它从数字中继续,就像我当前的文件一样?当我保存时,我希望它读取当前的最后一个文档 ID,或者简单地计算文档的数量,然后只需 + 1

来自 Andrei Cusnir 的见解,不支持在 Cloud Firestore 中计算文档。

现在我正在尝试 Andrei 的方法 2,按降序查询文档,然后使用 .limit 仅检索第一个。

更新

form.addEventListener('submit', (e) => 
e.preventDefault();
let query = db.collection('esequiz');
let getvalue = query.orderBy('id', 'desc').limit(1).get();
let newvalue = getvalue + 1;
db.collection('esequiz').doc(newvalue).set(
    question: form.question.value,
    right: form.right.value,
    wrong: form.wrong.value
);
form.question.value = '';
form.right.value = '';
form.wrong.value = '';
);

没有更多错误,而是下面的代码返回 [object Promise]

让 getvalue = query.orderBy('id', 'desc').limit(1).get();

所以当我的表单保存时,它保存为[object Promise]1,我不知道为什么会这样。有人可以告诉我如何返回文档 id 值而不是 [object Promise]

我认为是因为我确实指定了将文档 id 作为值,我该怎么做?

更新:最终解决方案

玩弄了 Andrei 的代码,这里是最终的有效代码。非常感谢安德烈!

let query = db.collection('esequiz');
//let getvalue = query.orderBy('id', 'desc').limit(1).get();
//let newvalue = getvalue + 1;    
query.orderBy('id', 'desc').limit(1).get().then(querySnapshot => 
    querySnapshot.forEach(documentSnapshot => 
        var newID = documentSnapshot.id;
        console.log(`Found document at $documentSnapshot.ref.path`);
        console.log(`Document's ID: $documentSnapshot.id`);
        var newvalue = parseInt(newID, 10) + 1;
        var ToString = ""+ newvalue;
        db.collection('esequiz').doc(ToString).set(
            id: newvalue,
            question: form.question.value,
            right: form.right.value,
            wrong: form.wrong.value
        );
    );
    );

【问题讨论】:

不是.length(),而是.length,因为它不是函数而是属性。所以试试let x = db.collection('esequiz').doc.length; @johannchopin 嗨,如前所述尝试了 .length 但它显示了一个新错误,在我的问题中更新 【参考方案1】:

如果我理解正确,您正在向 Cloud Firestore 添加数据,并且每个新文档的名称都会有一个递增的数字。

如果您查询所有文档,然后计算它们的数量,那么随着数据库的增加,您最终会得到许多文档读取。不要忘记 Cloud Firestore 对每个文档的读取和写入收费,因此如果您有 100 个文档并且您想添加 ID 为 101 的新文档,那么首先读取所有文档然后计算它们的方法将花费您100 次读取,然后 1 次写入。下一次它将花费您 101 次读取和 1 次写入。它会随着您的数据库增加而继续。

我看到的方式来自两种不同的方法:

方法一:

您可以拥有一个文档来保存数据库的所有信息以及下一个名称应该是什么。

例如

The structure of the database:
esequiz:
        0: 
          last_document: 2
        1: 
          question: "What is 3+3?
          right: "6"
          wrong: "0"
        2: 
          question: "What is 2+3?
          right: "5"
          wrong: "0"

所以流程如下:

    阅读文档“/esequiz/0”计为 1 次阅读 使用 ID 创建新文档:last_document + 1 计为 1 次写入 更新包含信息的文档:last_document = 3; 计为 1 次写入

这种方法需要对数据库进行 1 次读取和 2 次写入。

方法二:

您只能从数据库中加载最后一个文档并获取它的 ID。

例如

The structure of the database (Same as before, but without the additional doc):
esequiz:
        1: 
          question: "What is 3+3?
          right: "6"
          wrong: "0"
        2: 
          question: "What is 2+3?
          right: "5"
          wrong: "0"

所以流程如下:

    使用Order and limit data with Cloud Firestore 文档中描述的方法阅读最后一个文档。因此,您可以使用direction=firestore.Query.DESCENDINGlimit(1) 的组合,这将为您提供最后一个文档。 计为 1 次阅读 现在您知道已加载文档的 ID,因此您可以使用 ID 创建新文档:这将使用加载的值并将其增加 1。计为 1 WRITE

这种方法总共花费了您对数据库的 1 次读取和 1 次写入。


我希望这些信息对您有所帮助并解决您的问题。目前不支持在 Cloud Firestore 中计数文档。

更新

为了使排序工作,您还必须将 id 作为文档的一个字段包含在内,以便您可以根据它进行排序。我已经测试了以下示例,它对我有用:

数据库结构:

esequiz:
        1: 
          id: 1
          question: "What is 3+3?
          right: "6"
          wrong: "0"
        2: 
          id:2
          question: "What is 2+3?
          right: "5"
          wrong: "0"

如您所见,ID 设置为与文档的 ID 相同。

现在您可以根据该文件查询所有文件和订单。同时只能从查询中检索最后一个文档:

const Firestore = require('@google-cloud/firestore');
const firestore = new Firestore();

async function getLastDocument()

    let query = firestore.collection('esequiz');

    query.orderBy('id', 'desc').limit(1).get().then(querySnapshot => 
    querySnapshot.forEach(documentSnapshot => 
        console.log(`Found document at $documentSnapshot.ref.path`);
        console.log(`Document's ID: $documentSnapshot.id`);
    );
    );



OUTPUT:
Found document at esequiz/2
Document's ID: 2

然后您可以将 ID 加 1 以生成新文档的名称!

更新 2

因此,最初的问题是关于“如何使用具有增量 ID 的文档将数据存储在 Cloud Firestore 中”,目前您正面临与您的项目一起设置 Firestore 的问题。不幸的是,新提出的问题应该在另一篇 *** 帖子中讨论,因为它们与文档的增量 ID 的逻辑无关,最好每个问题保留一个问题,以便为正在寻找的成员提供更好的社区支持有关特定问题的解决方案。因此,在这篇文章中,我将尝试帮助您执行一个简单的 Node.js 脚本并解决最初的问题,即使用增量 ID 将文档存储到 Cloud Firestore。其他所有问题,关于如何在您的项目中设置它以及如何在您的页面中使用此功能,应在附加问题中解决,您还需要提供尽可能多的关于您正在使用的框架、项目设置的信息等等。

所以,让我们使用上述逻辑制作一个简单的 app.js:

    由于您已经拥有 Cloud Firestore,这意味着您已经拥有 Google Cloud Platform 项目(Firestore 所依赖的项目)并且已经启用了适当的 API。 否则将无法正常工作。 您在本教程中的指南是 Cloud Firestore: Node.js Client 文档。它将帮助您了解可以与 Firestore Node.js API 一起使用的所有方法。您可以找到用于添加、阅读、查询文档和更多操作的有用链接。 (稍后我将在此步骤中发布完整的工作代码。我刚刚分享了链接,以便您知道在哪里寻找其他功能) 转到Google Cloud Console Dashboard 页面。您应该使用已设置 Firestore 数据库项目的 Google 帐户登录。 在右上角,您应该会看到 4 个按钮和您的个人资料图片。第一个按钮是激活 Cloud Shell。这将在页面底部打开一个终端,其中已安装 linux OS 和 Google Cloud SDK。在那里,您可以与 GCP 项目中的资源进行交互,并在将代码用于项目之前在本地测试代码。 单击该按钮后,您会注意到终端将在页面底部打开。 为确保您已正确验证,我们将设置项目并再次验证帐户,即使默认情况下已完成。所以先执行$ gcloud auth login 在提示的问题上输入Y 并回车 单击生成的链接并在提示窗口中验证您的帐户 将生成的字符串复制回终端并回车。现在您应该已经过正确的身份验证了。 然后使用以下命令设置包含 Cloud Firestore 数据库的项目:$ gcloud config set project PROJECT_ID。现在您已准备好构建一个简单的 app.js 脚本并执行它。 新建一个app.js文件:nano app.js 在里面粘贴我的代码示例,可以在这个GitHub link 中找到。它包含完整的工作示例和许多解释每个部分的 cmets,因此最好通过 GitHub 链接共享而不是粘贴在这里。无需进行任何修改,此代码将完全执行您正在尝试执行的操作。我自己测试过了,它正在工作。 执行脚本为:node app.js 这会给您以下错误:

    错误:找不到模块“@google-cloud/firestore”

由于我们正在导入库@google-cloud/firestore,但还没有安装它。

    安装@google-cloud/firestore库如下:$ npm i @google-cloud/firestore。描述于DOC。 再次执行脚本:$ node app.js。 您应该看到例如Document with ID: 3 is written. 如果你再次执行,你应该看到例如Document with ID: 4 is written.

所有这些更改也应该出现在您的 Cloud Firestore 数据库中。如您所见,它正在加载最后一个文档的 ID,它正在创建一个新 ID,然后使用给定参数创建一个新文档,同时使用新生成的 ID 作为文档名称。这正是最初的问题。

所以我已经与您分享了完整的代码,这些代码可以正常工作并且完全符合您的要求。不幸的是,其他新提出的问题应该在另一个 *** 帖子中解决,因为它们与最初的问题无关,即“如何创建具有增量 ID 的文档”。我建议您按照这些步骤并有一个工作示例,然后尝试将逻辑实施到您的项目中。但是,如果您仍然面临如何在项目中设置 Firestore 的任何问题,那么您可以提出另一个问题。之后,您可以将这两种解决方案结合起来,您将拥有可以正常工作的应用程序!

祝你好运!

【讨论】:

理解是正确的,现在就试试看。谢谢指教! 嘿@Andrei Cusnir,我试过你上面的代码但它仍然无法工作,错误是firestore未在“direction = firestore.Query.DESCENDING”行中定义但我修改为firestore “db.collection('esequiz'),然后说“无法读取未定义的属性“DESCENDING”” @Basir La。我很抱歉造成混乱,显然您还需要多一个字段来根据它进行排序。请查看我的更新答案,因为此代码按预期对我有用。 我一直在尝试,但在某些代码上遇到了一些错误,例如第一个 const,我把它放在我的 app.js 中,它说它不能在模块外导入,使 firestore 在“让查询 = firestore.collection('esequiz');”未定义。我还尝试修改问题中的更新代码中所示的代码,但我仍然收到错误说需要第一个参数为非空字符串类型,但它是:自定义承诺对象@Andrei Cusnir 对不起,我还是个学生,不确定哪些代码适合哪里,但我目前正在将它们写在 app.js 上【参考方案2】:

我不认为您尝试获取集合长度的方式是正确的,我也完全不确定获得该长度的最佳方式是什么。因为您尝试实施的方法会在您尝试读取集合的所有记录时花费更多。

但可以通过其他方法获得所需的号码。

    开始将 ID 存储在记录中,并使用限制 1 和 ID 降序进行查询。 将最新的数字存储在另一个集合中,并在每次创建新记录时递增,并在需要时获取相同的数字。

如果在没有事务的情况下发出并发请求,这些方法可能会失败。

【讨论】:

有什么方法可以只读取集合中的文档数量? 这适用于小型收藏db.collection('...').get().then(snap => size = snap.size // will return the collection size );我建议您阅读以下文章。 [config9.com/apps/firebase/firebase-firestore-collection-count/] 谢谢!会看文章的。欣赏它 它无法计算内部文档的数量,而是返回 [object Promise],在数据库中它显示为 [object Promise] 1,而不是预期的整数。当我试图查看它时,也找不到文章页面 我正在使用一个小的集合,如上图所示,其中只有 3 个文档

以上是关于如何将具有动态 ID 的文档保存到 Cloud Firestore?总是在变化的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Cloud Firestore 中使用文档 ID 执行集合组查询

如何将具有自定义 ID 的文档添加到 Firestore

如何在flutter中将具有文档ID的自定义对象设置为firestore中的集合?

如何将图像保存到具有来自先前视图控制器的 id 的单独相册中

如何在将文档保存在猫鼬之前获取文档的 ID?

使用 django 动态添加输入字段并将数据保存到数据库