I have seen an increment counter with Cloud Functions referencing Realtime Database, but not Firebase Firestore yet.
I have a cloud function that listens for new documents:
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; });
I’m attempting the above transaction, but when I run firebase deploy
in terminal I get this error:
error Each then() should return a value or throw promise/always-return
functions predeploy error: Command terminated with non-zero exit code1
This is my first attempt at anything node.js, and I’m not sure I’ve written this right.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
There is now a much simpler way to increment/decrement a field in a document: FieldValue.increment()
. Your sample would be something like this:
const FieldValue = require('firebase-admin').firestore.FieldValue; var chainCounterRef = db.collection('counters').doc('chains'); chainCounterRef.update({ count: FieldValue.increment(1) });
See:
Method 2
If you want to safely increment a number in a document, you can use a transaction. The following code is taken directly from the linked page. It adds one to a field called population
in a document /cities/SF
after giving it some initial values:
// 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); });
Bear in mind that Firestore is limited to one write per second under sustained load, so if you’re going to be writing a lot, you will need to use a sharded counter instead.
Method 3
Here’s one potential solution. You could record the votes using sharding, but then use cloud functions to aggregate the shard totals and update your counter. That should reduce the number of document reads and therefore your Firestore bill.
Tutorial here: https://angularfirebase.com/lessons/firestore-cloud-functions-data-aggregation/
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0