【问题标题】:Firebase Admin in Cloud Functions data manipulation problemCloud Functions 中的 Firebase 管理员数据操作问题
【发布时间】:2021-10-06 13:48:20
【问题描述】:

Firebase 实时数据库结构

freepacks 包含两个重要元素:

  1. current,这是我将从移动应用下载的测验包ID(从quizpacks 检索)。
  2. history,这是一个节点,我在其中添加了我在 Cloud Functions 中随时间推移放入 current 的所有测验包 ID。

每次云功能执行时我需要做什么

第 1 步:history 中添加 current 的值和当前时间戳。

第 2 步:current 值替换为历史中的另一个测验包 ID。

完成

我是如何实现这个目标的

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

admin.initializeApp();

exports.scheduledFunction = functions.pubsub.schedule('* * * * *').onRun((context) => {

    // Current timestamp
    const dt = new Date();
    const timestamp = `${
        (dt.getMonth()+1).toString().padStart(2, '0')}/${
        dt.getDate().toString().padStart(2, '0')}/${
        dt.getFullYear().toString().padStart(4, '0')} ${
        dt.getHours().toString().padStart(2, '0')}:${
        dt.getMinutes().toString().padStart(2, '0')}:${
        dt.getSeconds().toString().padStart(2, '0')}`

    // Download the entire node 'freepacks'
    return admin.database().ref('quiz/freepacks').once('value').then((currentSnap) => {
        const currentPack = currentSnap.val().current;

        // Add current to history
        admin.database().ref('quiz/freepacks/history/' + currentPack).set(timestamp);
        
        // Download entire history node
        admin.database().ref('quiz/freepacks/history').once('value').then((historySnap) => {
            const history = historySnap.val();
            console.log('HISTORY: ' + history);

            // Download entire quizpacks node
            admin.database().ref('quiz/quizpacks').once('value').then((quizpacksSnap) => {
                for(quizpack in Object.keys(quizpacksSnap.val())) {
                    console.log('ITERANDO: ' + quizpack);
                    // Add the new current if it isn't in history
                    if (historySnap[quizpack] == undefined) {
                        admin.database().ref('quiz/freepacks/current').set(quizpack);
                        break;
                    }
                }
            });

        })

    });
    
});

我从之前的代码中得到了什么

起点:

首次执行:历史记录更新良好,但更新 current 无效

第二次执行广告等等... current 不再更新(卡在0)

我在 JavaScript 和 Firebase Admin 方面的经验是 ~0... 我的代码有什么问题?提前感谢您的帮助!

【问题讨论】:

  • 下一个 current 包应该是什么? for(quizpack in Object.keys(quizpacksSnap.val())) {} 这个 for 循环令人困惑。
  • @Dharmaraj 我使用这个 for 循环来迭代测验包中的所有键,并找到第一个不包含在历史记录中的键并放入当前
  • Promise 处理存在问题我正在调查,但您可以将您的数据库共享为 JSON 吗?您可以通过单击右上角的垂直省略号图标将其导出。我测试代码会更容易。
  • @Dharmaraj 是的。我删除了不属于问题的metadata 节点和freepacks 内的history 节点,应该自动创建:creativadev.altervista.org/db_export.json

标签: node.js firebase-realtime-database google-cloud-functions firebase-admin


【解决方案1】:

首先,所有读/写操作都会返回 Promise,因此您应该处理它们。在这个答案中,我使用了 async-await 语法。 .ref("quiz/freepacks") 获取完整节点,即当前节点和历史节点,因此您不必像在原始代码中那样再次查询历史节点。其他更改只是 Javascript 调整,例如使用 .find() 而不是 for-loop 等等..

尝试将您的功能更改为:

exports.scheduledFunction = functions.pubsub
  .schedule("* * * * *")
  .onRun(async (context) => {
    // Getting Date
    const dt = new Date();
    const timestamp = `${(dt.getMonth() + 1).toString().padStart(2, "0")}/${dt
      .getDate()
      .toString()
      .padStart(2, "0")}/${dt.getFullYear().toString().padStart(4, "0")} ${dt
      .getHours()
      .toString()
      .padStart(2, "0")}:${dt.getMinutes().toString().padStart(2, "0")}:${dt
      .getSeconds()
      .toString()
      .padStart(2, "0")}`;

    // Download the entire node 'freepacks'
    const currentSnap = await firebase
      .database()
      .ref("quiz/freepacks")
      .once("value");

    // Checking current free pack ID and array of previous free packs
    const currentPack = currentSnap.val().current || "default";
    const freeHistoryIDs = [
      ...Object.keys(currentSnap.val().history || {}),
      currentPack,
    ];

    // Add current free pack to free history
    await firebase
      .database()
      .ref("quiz/freepacks/history/" + currentPack)
      .set(timestamp);

    // Download entire quizpacks node
    const quizpacksSnap = await firebase
      .database()
      .ref("quiz/quizpacks")
      .once("value");

    const quizPackIDs = Object.keys(quizpacksSnap.val() || {});

    const newPack = quizPackIDs.find((id) => !freeHistoryIDs.includes(id));
    console.log(newPack);
    if (!newPack) {
      console.log("No new pack found")
    }
    return firebase.database().ref("quiz/freepacks/current").set(newPack || "none");
  });

【讨论】:

  • 错误:TypeError:无法在 /workspace/index.js:31:17 处的 Function.keys () 处将 undefined 或 null 转换为对象
  • @GabrieleFeudo 看起来我们在 undefined 上使用了 Object.keys(undefined)...请尝试更新,如果历史记录为空,则默认为 {}
  • 我发现了问题所在。节点history 在第一次执行时不在数据库中,但我在“// 检查当前免费包 ID 和先前免费包的数组”之前将代码移动到“// 将当前免费包添加到免费历史记录”下,并且现在工作正常。你救了我❤️
猜你喜欢
  • 2020-06-21
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
  • 2017-11-03
  • 2017-08-01
  • 1970-01-01
  • 2017-09-24
  • 2020-12-10
相关资源
最近更新 更多