I'm trying to implement a trigger using Firebase Functions, that duplicates some data in the database. I want to watch all additions at votes/user/vote, the structure is:
And the code I tried is:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.duplicateFeedback = functions.database.ref('/votes/{userId}/voteId')
.onWrite(event => {
const userId = event.params.userId;
const voteId = event.data.key();
const vote = event.data.val();
console.log(`New feedback from user ${userId}: { description: "${vote.feedback}", score: ${vote.rating}}`);
return;
});
But I can't even get it triggered.. Any clues what's wrong with my function? I bet is related with the reference, but I can't figure out what exactly.
Right now, the function is triggered by a write to
exports.duplicateFeedback = functions.database.ref('/votes/{userId}/voteId')
which would be triggered by something like this:
votes: {
00000_josemi_foo: {
voteId: {
// data
}
}
}
But you're not looking for the child voteId, you're looking for any child of {userId}, such as -33, so you need to use a wildcard:
exports.duplicateFeedback = functions.database.ref('/votes/{userId}/{voteId}')
Related
Just starting to use Firebase functions and have the sample working, but confused because the update event doesn't occur if I change the 'messages' collection to a different name, eg 'listings'. I change the word 'messages' in two places, on the 'add' and the 'makeUppercase' line. I get the response OK, it writes the data to the collection, but doesn't fire the event. Must be simple, but can't google it.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest(async (req, res) => {
// Grab the location parameter.
const inputcode = req.query.code || 'blank';
// Push the new message into Cloud Firestore using the Firebase Admin SDK.
const writeResult = await admin.firestore().collection('messages').add({inputcode: inputcode});
// Send back a message that we've succesfully written the message
res.json({result: `Message with ID: ${writeResult.id} added.`});
});
exports.makeUppercase = functions.firestore.document('/messages/{documentId}')
.onCreate((snap, context) => {
// Grab the current value of what was written to Cloud Firestore.
const inputcode = snap.data().inputcode;
// Access the parameter `{documentId}` with `context.params`
functions.logger.log('Uppercasing', context.params.documentId, inputcode);
const areacode = inputcode.toUpperCase();
const written = new Date();
return snap.ref.set({written, areacode}, {merge: true});
});
I'm using the local firebase emulator to do this test, by the way.
This is the new version, ony changing 'messages' to 'vvvv' in two places.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest(async (req, res) => {
// Grab the location parameter.
const inputcode = req.query.code || 'blank';
// Push the new message into Cloud Firestore using the Firebase Admin SDK.
const writeResult = await admin.firestore().collection('vvvvv').add({inputcode: inputcode});
// Send back a message that we've succesfully written the message
res.json({result: `Message with ID: ${writeResult.id} added.`});
});
exports.makeUppercase = functions.firestore.document('/vvvvv/{documentId}')
.onCreate((snap, context) => {
// Grab the current value of what was written to Cloud Firestore.
const inputcode = snap.data().inputcode;
// Access the parameter `{documentId}` with `context.params`
functions.logger.log('Uppercasing', context.params.documentId, inputcode);
const areacode = inputcode.toUpperCase();
const written = new Date();
return snap.ref.set({written, areacode}, {merge: true});
});
OK. Doug, your suggestion sank in after an hour or so! I've restarted everything and think that I understand. If I change the name in those two places, without restarting, the collection.add function takes place and I can see the record in the new collection, but the onCreate event didn't fire. I had to restart the whole service to restart buth parts. I was getting confused because one part was working and not the other. Thanks for your patience.
I have this function of Firebase Firestore, every time a new document is created in the collection pagos I am sending a transactional email through Sendgrid with the data of this new document created. It works well.
My question is how do I do the same function, that is, to send said email but only when the document is updated with a certain field (for example dataPago) Can it be done?
Here my function when creating a document:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const SENDGRID_API_KEY = functions.config().sendgrid.key
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
exports.pagoRealizado = functions.firestore
.document('pagos/{pagoId}')
.onCreate((snap, context) => {
const pagoId = context.params.pagoId;
const db = admin.firestore()
return db.collection('pagos').doc(pagoId)
.get()
.then(doc => {
const pago = doc.data();
const msg = {
from: 'xxx#gmail.com',
to: 'xxx#xxx.com',
templateId: 'd-3473a9cc588245b7b2a6633f05dafdd8',
substitutionWrappers: ['{{', '}}'],
dynamic_template_data: {
nombre: pago.dataCliente.nombre,
}
};
return sgMail.send(msg)
})
.then(() => console.log('email enviado!'))
.catch(err => console.log(err))
});
Instead of using an onCreate trigger, you can use an onUpdate trigger. This will fire whenever a matched document is changed in some way, but not created or deleted. You can read more about each kind of Firestore trigger in the documentation.
You can't set up a trigger on specific field in a document. The trigger will fire when any field in the document changes in any way. You will have to check the before and after states of the document snapshots delivered to the function in order to figure out if it's a change you want to act on. Again, the documentation talks about this in more detail.
I am looking for a solution to making the below code trigger onUpdate of a field value, rather than by the entire document.
Is it possible using the firebase-functions package to listen to a field value, let's say a field with a time stamp called lastUpdate? Alternatively, I am leaning toward a HTTP trigger called via onClick using axios but cannot find any resources, documentation or tutorials that help my understanding. If you know of any, I'd love to read them.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const sgMail = require('#sendgrid/mail');
try {
admin.initializeApp();
} catch (e) {
console.log(e);
}
var SENDGRID_API_KEY = functions.config().sendgrid.key;
sgMail.setApiKey(SENDGRID_API_KEY);
exports = module.exports = functions.firestore
.document('users/{id}')
.onUpdate(snap => {
const user = snap.data();
const msg = {
to: user.email,
from: 'example#example.com',
templateId: 'd-6c0e0385808c480ab475748a6eeed773',
dynamic_template_data: {
firstName: user.firstName,
email: user.email,
id: user.id
}
};
return sgMail.send(msg).catch(err => console.log(`${user.email} - ${err}`));
});
Cloud Firestore triggers Cloud Functions on a document level. There is no option to trigger a function only when a specific field in the document is changed. If you want that level of granularity for your triggers, consider using the realtime database.
I'm trying to do the following thing. I have my database like this
clients
|___clientnumber: 4
|___name1
|_device_token: kJ-aguwn7sSHsjKSL....
|_notificationtrigger: 8
What I want to do is that when a client puts a number in my app inside his node "name1" it will trigger a notification when clientnumber is 8 , so, client number will be 4, then 5, then 6 and so on till 8, when it hits 8 I wrote this function in order to send the user a notification telling him that the clientnumber 8 is ready.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendClientesNotification = functions.database.ref('/clients/clientnumber')
.onWrite((snapshot, context) => {
const newClient = snapshot.after.val();
const oldClient = snapshot.before.val();
console.log('New client: '+newClient);
console.log('Old client: '+oldClient);
// get the user device token
const getDeviceTokensPromise = admin.database()
.ref(`/clients/name1/device_token`).once('value');
const getClientNotificationTrigger = admin.database()
.ref(`/clients/name1/notificationtrigger`).once('value');
//I use a promise to get the values above and return, and then I create the notification
return Promise.all([getDeviceTokensPromise, getClientNotificationTrigger]).then(results => {
const devicetoken = results[0].val();
const clientNumberTrigger = results[1].val();
console.log('New notification for '+devicetoken+' for the number '+clientNumberTrigger);
if(clientNumberTrigger = newClient){
const payload = {
notification: {
title: "Alert",
body: "alert triggered",
icon: "default",
sound:"default",
vibrate:"true"
}
};
}
return admin.messaging().sendToDevice(devicetoken, payload);
});
});
Now, I will explain what I'm doing right here.
First I'm pointing to the reference clientnumber and successfully getting the value before and after it changes here
const newClient = snapshot.after.val();
const oldClient = snapshot.before.val();
console.log('New client: '+newClient);
console.log('Turno anterior: '+oldClient);
then I'm querying the values inside my client in order to have device_token and then notificationtrigger and using a promise to get the two values, comparing if they are identically and then returning a notification with the current user device_token
The errors I'm facing are this two
The first one I think is from this line
const clientNumberTrigger = results[1].val();
and the second one I don't know why is happening, I think that I need to add a conditional expression before my if statment
I'm starting up with firebase functions and slowly learning some javascript in the process.
as the error says: you are trying to compare two values using a single equals symbol (=) while you should use three instead:
switch this:
if(clientNumberTrigger = newClient) { ... }
to this:
if(clientNumberTrigger === newClient) { ... }
and at least this error should be gone.
I'm trying to write a firebase cloud function to delete automatically an event after is date is passed.
Based on this example Firebase example, I came to this, but when I'm uploading it on Firebase, it is running on Firebase side but it is not deleting events.
Do you guys have advices or see something wrong in my code ? Is it possible that the problem may coming from the trigger onWrite() ?
/* My database structure
/events
item1: {
MyTimestamp: 1497911193083
},
item2: {
MyTimestamp: 1597911193083
}
...
*/
// Cloud function to delete events after the date is passed
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.deleteOldItems = functions.database.ref('/events/{eventId}').onWrite((change) => {
const ref = change.after.ref.parent; // reference to the parent
const now = Date.now();
const oldItemsQuery = ref.orderByChild('MyTimestamp').endAt(now);
return oldItemsQuery.once('value').then((snapshot) => {
// create a map with all children that need to be removed
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
});
return ref.update(updates);
// execute all updates in one go and return the result to end the function
});
});
There is nothing wrong with the code, just update you cloud functions & admin:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.deleteOldItems = functions.database.ref("/events/{eventId}").onWrite((change, context) => {
if (change.after.exists() && !change.before.exists()) {
const ref = change.after.ref.parent;
const now = Date.now();
const oldItemsQuery = ref.orderByChild('MyTimestamp').endAt(now);
return oldItemsQuery.once('value').then((snapshot) => {
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
});
return ref.update(updates);
});
} else {
return null;
}
});
Run the following in the functions folder:
npm install firebase-functions#latest --save
npm install firebase-admin#5.11.0 --save
Reference here for more details
try to change
admin.initializeApp();
to :
admin.initializeApp(functions.config().firebase);