使用Cloud Functions for Firebase增加计数器

16

我曾经看到过一个使用云函数引用实时数据库的增量计数器,但还没有针对Firebase Firestore。

我有一个云函数监听新文档:

exports.addToChainCount = functions.firestore
    .document('chains/{name}')
    .onCreate((snap, context) => {

    // Initialize document
    var chainCounterRef = db.collection('counters').doc('chains');

    var transaction = db.runTransaction(t => {
        return t.get(chainCounterRef).then(doc => {
            // Add to the chain count
            var newCount = doc.data().count + 1;
            t.update(chainCounterRef, { count: newCount });
        });
    }).then(result => {
        console.log('Transaction success!');
    }).catch(err => {
        console.log('Transaction failure:', err);
    });
    return true;
});

我正在尝试以上交易,但是当我在终端中运行firebase deploy时,出现以下错误:

error Each then() should return a value or throw promise/always-return functions predeploy error: Command terminated with non-zero exit code1

这是我第一次尝试使用node.js,我不确定我是否写得正确。


1
有一个完整的文档页面介绍了Firestore中的分片计数器。在许多生产案例中需要进行分片的原因是因为Firestore文档在负载下只能处理一次写入。如果负载过大,任何超过这个限制的写入都将丢失,导致计数不准确。https://firebase.google.com/docs/firestore/solutions/counters - Doug Stevenson
@DougStevenson 谢谢,但我想使用云函数增加我的计数器。您是在暗示这样做不推荐吗? - Austin Berenyi
无论您在哪里编写文档,限制都存在。 - Doug Stevenson
@DougStevenson 有没有办法控制云函数触发新文档的速率?如果有的话,就可以使用队列系统更新计数器,如原帖所述。它偶尔会被堵塞,但速率限制将防止Firestore过载。 - Derrick Miller
2
@DerrickMiller,你所问的问题比在SO评论中解决的要复杂得多。这样的东西并没有内置在产品中。 - Doug Stevenson
好的,谢谢@DougStevenson提供的信息! - Derrick Miller
3个回答

38

现在有一种更简单的方法来增加/减少文档中的字段: FieldValue.increment()。您的示例将类似于以下内容:

const FieldValue = require('firebase-admin').firestore.FieldValue;
var chainCounterRef = db.collection('counters').doc('chains');
chainCounterRef.update({ count: FieldValue.increment(1) });

请查看:


是的,这应该是被接受的答案。这个新的添加有助于在文档中保留关于集合的元数据。非常方便!好答案。 - thewebjackal
这个只适用于Cloud Firestore还是也适用于Realtime Database? - Calvin
9
非常感谢您的夸奖和分享,@FrankvanPuffelen。为了使其正常工作,我必须添加 const FieldValue = require('firebase-admin').firestore.FieldValue; - Sukhi
使用 chainCounterRef.set({ count: FieldValue.increment(1) }); 可以使其在文档不存在时正常工作。 - John T
如果您有多个实例运行该函数并且正在使用该值,则此方法无法正常工作。例如,如果您将其用于增加发票号码,则有时会出现重复的情况。 - crushman
显示剩余3条评论

1
如果您想在文档中安全地增加一个数字,可以使用事务。以下代码直接引用自链接页面。在为文档/cities/SF赋予一些初始值后,它会将1添加到名为population的字段中。
// Initialize document
var cityRef = db.collection('cities').doc('SF');
var setCity = cityRef.set({
  name: 'San Francisco',
  state: 'CA',
  country: 'USA',
  capital: false,
  population: 860000
});

var transaction = db.runTransaction(t => {
  return t.get(cityRef)
      .then(doc => {
        // Add one person to the city population
        var newPopulation = doc.data().population + 1;
        t.update(cityRef, { population: newPopulation });
      });
}).then(result => {
  console.log('Transaction success!');
}).catch(err => {
  console.log('Transaction failure:', err);
});

请记住,Firestore在持续负载下仅限于每秒一次写入,因此如果您要进行大量写入,则需要使用分片计数器

谢谢这个参考。这很有帮助。我已经编辑了我的问题,以反映交易方法的添加。 - Austin Berenyi
1
现在返回从runTransaction返回的Promise。这是后台函数的标准要求。它对所有函数都是必需的,而不仅仅是事务。https://firebase.google.com/docs/functions/terminate-functions - Doug Stevenson

0

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