Skip to content

Instantly share code, notes, and snippets.

@saintplay
Last active October 17, 2021 17:00
Show Gist options
  • Save saintplay/3f965e0aea933a1129cc2c9a823e74d7 to your computer and use it in GitHub Desktop.
Save saintplay/3f965e0aea933a1129cc2c9a823e74d7 to your computer and use it in GitHub Desktop.
Add counter for Firestore Collection
// functions/income/counter.function.js
'use strict'
const functions = require('firebase-functions')
const admin = require('firebase-admin')
// Prevent firebase from initializing twice
try { admin.initializeApp(functions.config().firebase) } catch (e) {}
// My collection is called "incomes"
const incomeRef = functions.firestore.document('incomes/{incomeId}')
// My counter is allocated in `/counters/incomes`, maybe you wanna follow this structure instead: https://firebase.google.com/docs/firestore/solutions/counters
const counterRef = functions.firestore.document('counters/incomes')
// These references are not the same as Firestore DocumentReferences
// check https://firebase.google.com/docs/reference/functions/functions.firestore.DocumentBuilder
// Perform an increment when income is added
module.exports.incrementIncomesCounter = incomeRef.onCreate(event => {
const counterRef = event.data.ref.firestore.doc('counters/incomes')
counterRef.get()
.then(documentSnapshot => {
const currentCount = documentSnapshot.exists ? documentSnapshot.data().count : 0
counterRef.set({
count: Number(currentCount) + 1
})
.then(() => {
console.log('Incomers counter increased!')
})
})
})
// Perform an decrement when income is deleted
module.exports.decrementIncomesCounter = incomeRef.onDelete(event => {
const counterRef = event.data.ref.firestore.doc('counters/incomes')
counterRef.get()
.then(documentSnapshot => {
const currentCount = documentSnapshot.exists ? documentSnapshot.data().count : 0
counterRef.set({
count: Number(currentCount) - 1
})
.then(() => {
console.log('Incomers counter decreased!')
})
})
})
// Perform a fresh recount(this is expensive) when the counter is deleted (This is optional as well)
module.exports.recountIncomesCount = counterRef.onDelete(event => {
const incomesRef = event.data.ref.firestore.collection('incomes')
return incomesRef.get()
.then(querySnapshot => {
counterRef.set({
count: querySnapshot.docs.length
})
})
})
// functions/index.js
/** EXPORT ALL FUNCTIONS
*
* - Loads all `.function.js` files
* - Supports multiple exports from a single `.function.js` file
* - It is optimized with `FUNCTION_NAME` env and omiting `node_modules` as well
* - Every function from any file must have unique name
* - Default export is not supported (`module.exports = ...`), instead use: `module.exports.functionName = ...`
*
* Based on this thread:
* https://github.com/firebase/functions-samples/issues/170
*/
const glob = require('glob') // npm i -S glob
const files = glob.sync('./**/*.function.js', { cwd: __dirname, ignore: './node_modules/**' })
files.forEach(file => {
const functionModule = require(file)
const functionNames = Object.keys(functionModule)
functionNames.forEach(functionName => {
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
exports[functionName] = functionModule[functionName]
}
})
})
@AntonKL
Copy link

AntonKL commented Jan 27, 2019

Cool one! I can't get this one to work at current date, maybe the API has changed?
Keep getting Cannot read property 'firestore' of undefined, so I guess it won't init correctly!

@hheimbuerger
Copy link

The index.js works great for me, thanks!

@AntonKL I haven't tested the example function, but I'm using admin.firestore() to get a firestore reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment