【问题标题】:Firebase Cloud Functions onCreate object undefined when creating a counterFirebase Cloud Functions onCreate对象在创建计数器时未定义
【发布时间】:2019-11-04 21:19:04
【问题描述】:

我有一个名为dashboard 的根集合,在其中我有一个名为totalUserCountry 的文档。在本文档中,我有一个带有一堆国家/地区名称的属性。每个值都是一个数字。

这个想法是每次将新用户添加到数据库并添加 1 到总数时运行该函数。

但是,我遇到了一个错误。这是我的代码:

import * as functions from 'firebase-functions';
import admin = require('firebase-admin');

const db = admin.firestore();

export const onAddUser = functions.firestore.document('users/{userID}')
    .onCreate(async (snapshot, context) => {
        let snapCountry = snapshot.get('country');
        snapCountry.toLowerCase();

        return db.runTransaction(async transaction => {
            const dashboardPath = db.collection('dashboard').doc('totalUserCountry');
            const dashSnap = await transaction.get(dashboardPath);
            const dashTotalUserData = dashSnap.data();
            const changes = { snapCountry: dashTotalUserData.snapCountry + 1 };
        })
    });

我得到的错误是

对象可能是'未定义'.ts(2532)

const changes = { snapCountry: dashTotalUserData.snapCountry + 1 }; 语句中的 dashTotalUserData 会出现这种情况。

有什么提示或建议吗?

【问题讨论】:

  • 是哪个物体向你抛出了这条线?
  • 嘿@andresmijares dashTotalUserData const changes = { snapCountry: dashTotalUserData.snapCountry + 1 };

标签: javascript node.js firebase google-cloud-firestore google-cloud-functions


【解决方案1】:

如果dashSnap 快照不存在,data() 可以返回undefined

因此,您应该按照以下方式调整您的代码:

  if (dashTotalUserData) {
    const changes = { snapCountry: dashTotalUserData.snapCountry + 1 };
    //....
  }

另外注意,你需要在你的事务中返回update()方法返回的promise,见https://firebase.google.com/docs/firestore/manage-data/transactions#transactions

在您当前的代码中,增量值没有更新。


最后,如果我理解正确的话,通过如下方式构建一个对象:

const changes = { snapCountry: dashTotalUserData.snapCountry + 1 };

您计划在totalUserCountry 文档中更新名称与snapCountry 值对应的字段的值。

请注意,此对象将更新 snapCountry 字段,而不是名为 usabelgiumfrance 等的国家/地区字段。

如果这个理解是正确的,你应该使用square-bracket notation,如下:

let changes = {};
changes[snapCountry] = dashTotalUserData.snapCountry + 1;

【讨论】:

  • 是的,我确实添加了transaction.update() 方法。你是对的,它写的是snapCountry而不是国家名称。无论如何?
  • 查看更新:您应该使用方括号表示法
  • 谢谢你!效果很好!非常感谢!
【解决方案2】:

Firestore 实际上本身就支持atomic increment,因此您根本不需要进行事务处理,这可以显着简化(而且更高效,因为更新完全发生在服务器端!)。

您可以这样做,而不是返回整个 db.runTransaction 块:

...
        snapCountry.toLowerCase();

        const dashboardPath = db.collection('dashboard').doc('totalUserCountry');
        return dashboardPath.update(snapCountry,
            admin.firestore.FieldValue.increment(1));
    });

此代码还避免了当前字段可能不存在的问题,因为 increment 将在传递给 increment 的值处创建字段(例如,如果它不存在,则假定它以前为零)。

当然,Firestore 也有一个扩展限制,即每个文档每秒只能更新一次,因此随着您的应用程序扩展,该计数器文档将开始受到重创。

确实,Firestore 记录了整个 solution for distributed counters,它将增量分片到许多文档中,然后在读取时从所有文档中汇总结果。从长远来看,这样的事情比增加单个文档中的单个字段更具可扩展性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-25
    • 2017-12-13
    • 1970-01-01
    • 2018-01-02
    • 1970-01-01
    相关资源
    最近更新 更多