Cloud Firestore trigger not working for Cloud function - javascript

I am trying to invoke a Cloud Function using the Cloud Firestore trigger. Basically, my cloud function is taking a full export of my sub collection 'reviews' whenever a new document is added to 'reviews'. I have around 6-7 documents inside my 'reviews' sub collection. I deployed the function through the console and the deployment completed. However, this function is not getting triggered whenever I add a new document to my 'reviews' sub collection. Can someone please tell me what could be the issue?
Trigger type: Cloud Firestore (Beta)
Event type: providers/cloud.firestore/eventTypes/document.write
Document Path: test_restaurant/{reviews}
EDIT:
I want my cloud function to only export the new documents added to my firestore to my GCP bucket. Below is the function I am trying to write:
const functions = require('firebase-functions');
const firestore = require('#google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();
const bucket = 'gs://ABC/trigger_test'
exports.newFirestoreBackup = functions.firestore
.document('test_restaurant/{Id}/reviews/{Id}')
.onWrite((change, context) => {
const databaseName = client.databasePath(
// process.env.GCLOUD_PROJECT,
"FS-123",
'(default)'
);
return client
.exportDocuments({
name: databaseName,
outputUriPrefix: bucket,
// Leave collectionIds empty to export all collections
// or define a list of collection IDs:
// collectionIds: ['users', 'posts']
collectionIds: ['reviews'],
})
.then(responses => {
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
return response;
})
.catch(err => {
console.error(err);
});
});
CONSOLE SNIPPET:

You don't share any code, but if you want your Cloud Function to be triggered "whenever [you] add a new document to the reviews subcollection", it should be declared with the following path:
exports.createUser = functions.firestore
.document('test_restaurant/{restaurantId}/reviews/{reviewId}')
.onCreate((snap, context) => {...});
You could use an onWrite() trigger as well, with the same path.

Related

Firebase Funtions push notifications

I'm new to firebase and there is something I can't do. I want to send a notification to the phone with firebase functions. I want to receive notifications on the phone when someone follows me. My Firebase collection is as in the photo. I want to access the Followers array and send its information with notification. The codes I could write are as follows. What do I need to add?
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendPushNotification = functions.firestore.document('/users/{uid}').onCreate((snap, context) => {
var values = snap.data();
var token = values.fcmTokens;
var payload = {
notification: {
title: values.title,
body: values.message
}
}
return admin.messaging().sendToDevice(token, payload);
});
First, onCreate() function is triggered when a document is created. I assume followers array will be updated everytime someone follows a user? In that case you should be using onUpdate() that'll trigger the function when the document is updated. You can just check if length of followers array has changed in the update, if yes then send the notification as shown below:
exports.sendPushNotification = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const previousValue = change.before.data();
if (newValue.followers.length > previousValue.followers.length) {
// followers count increased, send notification
const token = newValue.fcmTokens;
const payload = {
notification: {
title: "New Follower",
body: "Someone followed you"
}
}
await admin.messaging().sendToDevice(token, payload);
}
return null;
});
Here, we send notification only if the followers field has changed since this function will trigger whenever any field in this user document is updated.
If you want to specify who followed the user, then you'll have to find the new UID added in followers array and query that user's data.
Firestore documents have a max size limit of 1 MB so if a user can have many followers then I'll recommend creating a followers sub-collection. Then you'll be able to use onCreate() on the sub-document path /users/{userId}/followers/{followerId}

How to retrieve a document from firestore using firebase function and add new data from another firestore document?

I'm new with firebase cloud function, and have some trouble to get() et set() data from firestore documents within a firebase function.
Here what I try to do within a firebase function :
Access the data of the new document "doc1" when its created in firestore;
Access the value associated with the "user" field of "doc1";
This value is of type "reference", i.e. a path pointing to another document in another firestore collection "col2/doc2"
Use this path to access the second document "doc2" and retrieve two new values belonging to this second document to add it to the first document "doc1";
Final goal is to add the values belonging to the fields "name" and "city" of "doc2" to "doc1" ;
Here what I try up to now, I'm sure I have few problems with syntax and use of then() chain, but the main idea is there :
exports.addDataFromDoc2ToDoc1 = functions.firestore
.document('col1/{doc1Id}')
.onCreate((change, context) => {
const doc1Id = context.params.doc1Id
const doc1 = change.data()
const refToDoc2 = doc1.refField
const doc2Data = refToDoc2.get()
.then(function (documentSnapshot) {
if (documentSnapshot.exists) {
doc2Data = documentSnapshot.data()
return doc2Data
}
})
const doc1Name = doc2Data.doc1Name
const doc1City = doc2Data.doc1City
db.collection('col1')
.doc(doc1Id)
.set({
name: doc1Name,
city: doc1City
});
})
I start from firebase documentation :
https://firebase.google.com/docs/functions/firestore-events
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.writeToFirestore = functions.firestore
.document('some/doc')
.onWrite((change, context) => {
db.doc('some/otherdoc').set({ ... });
});
It would be appreciated if someone could help me with this task, and how I can restructure my algorithm to be more efficient maybe?
Thank you very much for your help and your time!
Since the field is of type Reference, you need to use the path property of the DocumentReference object, as follows:
exports.writeToFirestore = functions.firestore
.document('col1/{doc1Id}')
.onCreate((snap, context) => {
const newValue = snap.data();
const refToDoc2 = newValue.refField;
return db.doc(refToDoc2.path).get()
.then((doc) => {
if (doc.exists) {
const name = doc.data().name;
const city = doc.data().city;
return snap.ref.update({ name, city })
} else {
throw new Error('No document corresponding to the Reference!')
}
})
.catch(error => {
console.log(error);
return null;
});
});
In addition, note how we chain the promises returned by the asynchronous Firestore methods and, very important, how we return this promise chain.
Also note that we use the update() method, instead of the set() one.

Setting collection name in Firebase function

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.

Firebase functions update document / sendgrid

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.

Trigger Firebase function onUpdate of document field value

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.

Categories

Resources