如何将具有动态ID的文档保存到Cloud Firestore中?始终在变化。

3
我正在使用Cloud Firestore作为我的数据库。这是我的网页上创建一个名为“esequiz”的新文档到Cloud Firestore集合的表单代码。那么,如何编写代码,使其始终将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。 enter image description here 来自Andrei Cusnir的见解,Cloud Firestore不支持计算文档数。
现在我正在尝试Andrei的第二种方法,按降序查询文档,然后使用.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]

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

因此,当我的表单保存时,它保存为[object Promise]1,我不知道为什么会这样。有人能告诉我如何返回文档ID值而不是[object Promise]吗?
我认为这是因为我没有指定将文档ID作为值提取出来,那么我该怎么做呢? enter image description here 更新:最终解决方案
通过与Andrei的代码尝试,这里是最终可行的代码。非常感谢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
@johannchopin 你好,我尝试了你提到的 .length,但是出现了一个新的错误,我已经在我的问题中更新了。 - Baboy
2个回答

3

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

如果您查询所有文档,然后计算它们的数量,那么随着数据库的增长,您将获得许多文档读取。不要忘记,Cloud Firestore按文档读取和写入收费,因此如果您有100个文档,并且想要添加新文档并将其命名为ID:101,则采用先读取所有文档然后计数的方法将会花费您100次读取和一次写入费用。下一次它将花费您101次读取和1次写入。随着数据库的增长,这将继续进行。

我认为有两种不同的方法:

方法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"

所以,步骤如下:
  1. 读取文档“/esequiz/0” 算作1次读取
  2. 创建具有ID的新文档:last_document + 1 算作1次写入
  3. 更新保存信息的文档:last_document = 3; 算作1次写入

这种方法会向数据库造成1次读取和2次写入的开销。

方法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"

因此,流程如下:
  1. 使用云 Firestore 中的排序和限制数据文档中描述的方法读取最后一个文档。这样,您可以使用direction=firestore.Query.DESCENDINGlimit(1)的组合,这将为您提供最后一个文档。计为 1 次读取
  2. 现在您知道已加载文档的 ID,因此可以创建新文档,并将其 ID 设置为使用已加载的值并将其增加 1。计为 1 次写入

这种方法总共耗费了您对数据库 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与项目的问题。不幸的是,新提出的问题应在另一个Stackoverflow帖子中讨论,因为它们与具有递增ID的文档的逻辑无关,并且最好每个问题保持一个问题,以为寻找解决方案的成员提供更好的社区支持特定问题。 因此,在这篇文章中,我将尝试帮助您执行一个简单的Node.js脚本并解决最初的问题,即将文档存储到具有递增ID的Cloud Firestore文档中。 对于如何在您的项目中设置此功能以及如何在页面上使用此功能等其他所有内容,都应在其他问题中进行讨论,其中您还需要尽可能多地提供有关所使用的框架,项目设置等的信息。

因此,让我们用上述描述的逻辑使一个简单的app.js工作:

  1. 既然您已经使用Cloud Firestore工作,这意味着您已经拥有了Google Cloud Platform项目(其中Firestore依赖)和正确的API已启用。否则它将无法工作
  2. 在本教程中,您的指南是Cloud Firestore: Node.js Client文档。它将帮助您了解所有可以使用Firestore Node.js API进行的方法。您可以找到有关添加、读取、查询文档以及许多其他操作的有用链接。(我稍后会发布完整的工作代码在这些步骤中。我只分享链接,让您知道如何查找其他功能
  3. 转到Google Cloud Console Dashboard页面。您应该使用存储有Firestore数据库项目的Google帐户登录。
  4. 在右上角,您应该看到4个按钮和您的个人资料图片。第一个按钮是激活Cloud Shell。这将在页面底部打开一个带有Linux操作系统和Google Cloud SDK的终端。在那里,您可以与GCP项目中的资源交互,并在使用它们之前在本地测试代码。
  5. 点击该按钮后,您会注意到终端将在页面底部打开。
  6. 为确保已正确验证身份,即使默认情况下已经完成了项目设置和身份验证,我们也会重新设置项目并再次验证帐户。因此,请先执行$ gcloud auth login
  7. 在提示的问题上键入Y,然后按Enter
  8. 点击生成的链接,在弹出的窗口上验证您的帐户
  9. 将生成的字符串复制回终端,并按Enter键。现在,您应该已经得到了适当的身份验证。
  10. 然后,使用以下命令设置包含Cloud Firestore数据库的项目:$ gcloud config set project PROJECT_ID。现在,您已准备好构建一个简单的app.js脚本并执行它了。
  11. 创建一个新的app.js文件:nano app.js
  12. 粘贴其中的代码示例,可以在此GitHub链接中找到。它包含完全工作的示例和许多注释,解释了每个部分,因此最好通过GitHub链接共享它,而不是在此粘贴。在不进行任何修改的情况下,此代码将执行您要执行的操作。我自己进行了测试,它是有效的。
  13. 将脚本作为以下方式执行:node app.js
  14. 这将给您以下错误:

    Error: Cannot find module '@google-cloud/firestore'

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

  1. 按照如下方式安装@google-cloud/firestore库:$ npm i @google-cloud/firestore。详见文档
  2. 再次执行脚本:$ node app.js
  3. 您应该看到类似于Document with ID: 3 is written.的东西。
  4. 如果再次执行,您应该看到类似于Document with ID: 4 is written.的东西。

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

所以我与您分享了完整的代码,可以正常工作并确切地做到了您想要做的事情。不幸的是,其他新提出的问题应该在另一篇Stackoverflow文章中解决,因为它们与最初的问题“如何创建具有增量ID的文档”无关。建议您遵循这些步骤,拥有一个可工作的示例,然后尝试将逻辑实施到您的项目中。然而,如果您仍然在如何设置Firestore在您的项目中遇到任何问题,则可以提出另一个问题。之后,您可以结合两种解决方案,就会有一个工作的应用程序!

祝你好运!


理解正确,现在将尝试一下。感谢启发! - Baboy
嘿,@Andrei Cusnir,我尝试了你上面的代码,但仍然无法工作,错误是在“direction = firestore.Query.DESCENDING”这一行中未定义firestore。但我修改了firestore为“db.collection('esequiz')”,然后它说“无法读取未定义的属性“DESCENDING”。 - Baboy
@Basir La。对于造成的困惑我感到抱歉,显然您还需要有一个字段来进行排序。请查看我的更新答案,因为这段代码对我来说可以正常工作。 - Andrei Cusnir
抱歉,我仍然是一名学生,不确定哪些代码适用于哪里,但我目前正在app.js上编写它们。 - Baboy
我该如何将此功能添加到我的表单中,因为流程顺序应该是用户填写表单,点击按钮,然后保存到我的Firestore中。 - Baboy
显示剩余3条评论

0

我认为你尝试获取集合长度的方式不正确,而且我也不确定最佳方法是什么。因为你尝试实现的方法会花费更多的时间,因为你要读取集合中的所有记录。

但是有其他方法可以获得所需的数量。

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

如果没有事务并发请求可能会导致这些方法失败。


有什么方法可以只读取集合中文档的数量? - Baboy
它无法计算内部文档的数量,而是返回了[object Promise],在数据库中显示为[object Promise] 1,而不是预期的整数。 当我尝试查看文章页面时,未找到该页面。 - Baboy
我正在使用一个小集合,就像上面的图片所示,其中只有3个文档。 - Baboy
是的,我正在回应您上面分享的代码,我尝试了一下,保存后结果为[object Promise] 1。 - Baboy
让我们在聊天中继续这个讨论 - Saurav Suman
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接