如何使用云函数将数据写入云 Firestore

Posted

技术标签:

【中文标题】如何使用云函数将数据写入云 Firestore【英文标题】:How to write data to cloud Firestore using cloud Functions 【发布时间】:2020-03-04 03:46:20 【问题描述】:

对于我在 Flutter 中构建的调度应用程序,我正在尝试使用云功能和 cron 作业将数据写入我的云 Firestore 数据库,以使我的应用程序更加自我维持。我被困在第一步,试图让我的云功能将数据写入我的云 Firestore 数据库。

下面我在 github 上包含了指向图片的链接,这些图片说明了我当前数据在 Firestore 中的结构。我想要的是将命名文档添加到具有“小时”子集合的“天”集合中,其中有更多具有“小时”和“保留”字段的命名文档。

图一:https://github.com/winckles/rooster/blob/master/Schermafbeelding%202019-11-07%20om%2014.27.55.png?raw=true

图二:https://github.com/winckles/rooster/blob/master/Schermafbeelding%202019-11-07%20om%2014.28.26.png?raw=true

下面我还介绍了我在 Firestore 中获取数据的尝试。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

// admin.firestore().collection('days').add(original: original). then(writeResult => 
//
// );

exports.updateData = functions.https.onCall((data, context) => 
    const days = admin.firestore().collection('days');
    return days.doc(data['2019-11-08/hours/001']).set(
        hour: '08:00-09:00',
        reserved: '',
    );
);

理想情况下,我希望云功能同时将 14 个文档(例如 2019-11-06 到 2019-11-19)添加到“days”集合中。然后,这些文档每个都有一个子集合“小时”,其中包含来自第二个屏幕截图的数据(因此文档 001、002、003 等具有小时和保留字段)。

我阅读了有关云功能的文档,并且大部分发现了将数据写入 Firestore 时的触发器,但这不是我想要的。我还尝试了快速入门功能示例,但没有成功。它不应该太难,但我似乎无法弄清楚。我正在使用 javascript 编写云函数。任何帮助/提示将不胜感激!

【问题讨论】:

【参考方案1】:

你没有具体说明什么不适合你。但是,我注意到的第一件事是您没有从云函数上下文中正确调用initilizeApp。对于云函数,您不需要任何参数,因为默认凭据应该适合您(除非您已经做了一些非常不寻常的事情)。

这是一个云函数,可以对您想要的行为进行建模。它没有完成全部行为,因为我发现编写日期处理代码可能会分散您所询问问题的主要部分,即 Firestore 和函数代码本身。

同样,这使用 https 函数(因为它对我来说更容易测试:),使用可调用函数(或任何其他函数类型,例如,如果您使用的是 cron 作业,则为预定函数)需要稍微调整它(例如,对于可调用函数,您需要将声明更改回 onCall 并更改最终的 .then() 调用以返回您想要返回的值)。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const db = admin.firestore();

exports.doIt = functions.https.onRequest((request, response) => 
    const days = db.collection('days');
    const writePromises = [];

    ['2019-11-08', '2019-11-09'].forEach((day) => 
      const documentReference = days.doc(day);
      writePromises.push(documentReference.set(reserved: ''));

      const hoursReference = documentReference.collection('hours');
      const dataMap =  '001': '08:00-09:00',
                        '002': '09:00-10:00',
                        '003': '10:00-11:00',
                        '004': '11:00-12:00' ;
      Object.keys(dataMap).forEach((hour) => 
        writePromises.push(hoursReference.doc(hour).set(
          hour: dataMap[hour],
          reserved: ''
        ))
      );
    );

    return Promise.all(writePromises)
      .then(() =>  response.send('ok'); )
      .catch((err) =>  console.log(err); );
  );

请注意,当您编写整个结构时,您需要为每个文档的写入付费。但实际上并没有办法避免这种情况,因为写入是按文档计费的,而不是按请求计费的。

同样,您可能需要考虑将其作为batched write 执行——上面的示例只是展示了一种基本的写作方法。批量写入会将所有文档自动放入数据库。但是,批量写入限制为 500 次更新,您将在大约 21 天的数据(21 天 * 24 小时)内达到这些更新。这看起来与上面非常相似(以下只是函数本身的内容:

    const days = db.collection('days');
    const batch = db.batch();

    ['2019-11-08', '2019-11-09'].forEach((day) => 
      const documentReference = days.doc(day);
      batch.set(documentReference, reserved: '');

      const hoursReference = documentReference.collection('hours');
      const dataMap =  '001': '08:00-09:00',
                        '002': '09:00-10:00',
                        '003': '10:00-11:00',
                        '004': '11:00-12:00' ;
      Object.keys(dataMap).forEach((hour) => 
        batch.set(hoursReference.doc(hour), 
          hour: dataMap[hour],
          reserved: ''
        );
      );
    );

    return batch.commit()
      .then(() =>  response.send('ok'); )
      .catch((err) =>  console.log(err); );

我确实有点想知道为什么您需要在云功能中执行此操作,而不是通过直接从您的应用程序调用 Firestore。无论如何,以上内容应该可以让您开始。

【讨论】:

太棒了,谢谢你的作品!我还有一个问题;如果我希望 001、002 等的时间完全不同(例如,001 的时间为 08:00-09:00,002 的时间为 09:00-10:00),那在代码中会怎样?至于为什么不是直接从应用程序调用;我认为 cronjobs 仅适用于云功能,并且我认为当代码的更改只能通过应用商店完成时,以这种方式进行更新会更容易。总而言之,我只是一个试图让mvp启动并运行的菜鸟,我会调查你所说的!再次感谢! 我省略了这部分,因为 (a) 它增加了答案中隐藏的复杂性(正如我所提到的),但此外 (b) 我无法为 '005' 想出任何合理的方法成为“12:00-13:00”(来自您的示例图像),而不仅仅是通过硬编码映射。但是,您可以通过将关联数组作为映射并在内部循环中循环其键/值而不是平面数组来做到这一点。我将添加一个示例。 非常感谢!我已经为此苦苦挣扎了一段时间,而您刚刚解决了!这是让我的 mvp 启动和运行的一大步,你甚至无法想象!【参考方案2】:

如果您想在 firebase 中执行 cron,使用 Google Cloud Scheduler 可能会更好,但要小心这种方法有不同的分解

    exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun((context) => 
  console.log('This will be run every 5 minutes!');
  return null;
);

您可以在以下位置了解更多信息:

https://firebase.google.com/docs/functions/schedule-functions

【讨论】:

以上是关于如何使用云函数将数据写入云 Firestore的主要内容,如果未能解决你的问题,请参考以下文章

如何使用云功能从 Firestore 中删除数据

发生错误时如何中止 Firestore 事务

您如何避免使用 firebase 云功能可能出现的竞争情况?

云功能有时会在触发另一个云功能后写入 FireStore

如何从云函数动态地在 Cloud Firestore 中创建集合

在云功能中使用 Cloud Firestore