Comparing Cloud Functions for Firebase database triggers onCreate(), onWrite(), onUpdate(), when to use? - firebase

It's a simple question, I have seen all these methods addressed in the title in the documentation but all the examples are using onWrite() for triggering database events which then one would have to check to make sure it's not for removing or updating with
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onWrite(event => {
...
// Only edit data when it is first created.
if (event.data.previous.exists()) {
return;
}
// Exit when the data is deleted.
if (!event.data.exists()) {
return;
}
...
});
The only examples with onCreate() for instance, are related to auth events. Is there a reason or am I just being paranoid? Why not just use onCreate() and not bother the check?

onCreate(), onUpdate() and onDelete() were added in the Firebase SDK for Cloud Functions (v0.5.9) release on 7 July 2017. This is detailed in the release notes:
An updated beta release of the Firebase SDK for Cloud Functions
(v0.5.9) is now available. It includes the ability to listen to
granular create, update, and delete database events by using the
onCreate(), onUpdate(), and onDelete() methods.
Prior to that release, the only database event handler was onWrite(). The documentation has not yet been updated to include examples of the new handlers.
There is no reason not to take advantage of the convenience of the new handlers.

Related

Deploying Cloud Firestore Trigger function from GCP Console

I have a function that is fired on a onUpdate trigger from my cloud firestore database.
The function not being called at all when I change my database.
I did not deploy the function using firestore CLI, instead I deployed it using the GCP Console.
Here is the function:
exports.NotificationListener = functions
.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
const userId = context.params.userId.toString();
const eventId = context.eventId;
console.log('EventId:' + eventId);
console.log('Change in:' + userId);
return 200;
});
Here is the deployment information from the GCP console (showing the trigger):
Finally, here is the Cloud Firestore schema:
I want to monitor any changes to any "USER" in the collection: "/user", hence I am using "user/{userId}".
Why is this function not being called when I change the database ?
EDIT 1
A little information about my environment:
I have my entire project core in a TypeScript file. I have over 40 HTTPS triggered functions that are currently online.
I add a new function in my TS file, then I do a npm run build to compile and get the JS file.
Finally, I go to Google Cloud Console and create a function and choose "Zip Upload" and upload the compiled JS file (obviously, along with the required JSON files for getting Database URL, Authentication etc.)
This approach works perfectly fine, at least for HTTP triggered firestore functions.
Now I repeated the same steps as above for the onUpdate trigger and just instead of choosing HTTP trigger, I chose Cloud Firestore trigger. The trigger information can be found above in the screenshot.
onUpdate is not being fired on DB changes.
EDIT 2
My event trigger function NotificationListener is showing up in the firebase console functions list along with my other 40 HTTPS functions. But it is not being called.
#doug-stevenson, your answer seems to have disappeared, I am not sure why.
Anyway, I found the reason why it wasn't working.
My firebase database was in project "Placeholder 1" and my GCP functions were in project "Placeholder 2".
Now, I was able to update the "Placeholder 1" DB from GCP functions (in "Placeholder 2") using firabse-functions API because I set the DatabaseURL to "Placeholder 1".
But, just setting the DatabaseURL to the desired database doesn't work if you want to LISTEN to the database for changes. You actually need to have the function in the same project otherwise it is not able to subscribe and listen for events.
I think it's a little inconsistent that you can read/write to a DB from different projects, but to listen for events, function needs to be in same project.
Or maybe I am missing something fundamental that caused this confusion for me.

trigger function on firebase deploy functions

Does anyone know if there is an easy way to trigger a function everytime i re-deploy some funciont to firebase?
I have an specific firabase functions which i define inside GCP (this way when i do "firebase deploy" it doesnt re-deploy, unnisntal or touch in any form my current function)
but sometimes i might update this function manually on GCP and i would like to trigger a inner function of its code everytime it happens... is it possible?
ex:
exports.decrementAction = (req, res) => {/*do stuff*/res.status(200).send("ok")};
function auxiliary(){
//to be called on re-deploy
}
Unfortunately, there isn't an easy way for you to trigger a function within a code that is being redeployed. Since this code is only being deployed at the moment, this wouldn't be possible to be done automatically.
The alternative would be to have this function separately from the "root" function in the moment of deploying and use triggers to run this other Cloud Function, when the first is redeployed. This way, it would be possible to run it based in the deployment of the other.
You can get more information on the triggers available for Cloud Functions here: Calling Cloud Functions. With them, you should be able to configure the timing for the execution.
Besides that, it might be worth it to raise a Feature Request for Google's to verify the possibility of adding this in future releases.
Let me know if the information clarified!
I think there exists a manner.
With Pub/Sub you can catch logs from Stackdriver (docs). Those services allow you to store only the logs related to the deployment of a Cloud Function.
The store could be, for instance, Cloud Firestore. As you should know, there is available a trigger for Cloud Firestore events.
Finally, every time an event log related to a function's deployment is generated, it will be stored and triggers a function attached to that event. In the function, you can parse or filter the logs.

Firebase: Cloud Functions, How to Cache a Firestore Document Snapshot

I have a Firebase Cloud Function that I call directly from my app. This cloud function fetches a collection of Firestore documents, iterating over each, then returns a result.
My question is, would it be best to keep the result of that fetch/get in memory (on the node server), refreshed with .onSnapshot? It seems this would improve performance as my cloud function would not have to wait for the Firestore response (it would already have the collection in memory). How would I do this? Simple as populating a global variable? How to do .onSnaphot realtime listener with cloud functions?
it might depend how large these snapshots are and how many of them may be cached ...
because, it is a RAM disk and without house-keeping it might only work for a limited time.
Always delete temporary files
Local disk storage in the temporary directory is an in-memory file-system. Files that you write consume memory available to your function, and sometimes persist between invocations. Failing to explicitly delete these files may eventually lead to an out-of-memory error and a subsequent cold start.
Source: Cloud Functions - Tips & Tricks.
It does not tell there, what exactly the hard-limit would be - and caching elsewhere might not improve access time that much. it says 2048mb per function, per default - while one can raise the quotas with IAM & admin. it all depends, if the quota per function can be raised far enough to handle the cache.
here's an example for the .onShapshot() event:
// for a single document:
var doc = db.collection('cities').doc('SF');
// this also works for multiple documents:
// var docs = db.collection('cities').where('state', '==', 'CA');
var observer = doc.onSnapshot(docSnapshot => {
console.log(`Received doc snapshot: ${docSnapshot}`);
}, err => {
console.log(`Encountered error: ${err}`);
});
// unsubscribe, to stop listening for changes:
var unsub = db.collection('cities').onSnapshot(() => {});
unsub();
Source: Get realtime updates with Cloud Firestore.
Cloud Firestore Triggers might be another option.

How to remove listener for DocumentSnapshot events (Google Cloud FireStore)

I'm new in Google Cloud FireStore.
The Document object has a function call onSnapshot to attaches a listener for DocumentSnapshot events.
Is there a function to remove that listener (like offSnapshot)? If not how can I implement it?
In case of the web and node.js SDK, calling onSnapshot returns a function that you need to save in a variable and call when you want to remove the listener.
var unsubscribe = db.collection("cities").onSnapshot(function (querySnaphot) {
// do something with the data.
});
// Stop listening to changes
unsubscribe();
The other SDKs offer similar functionality.
See https://firebase.google.com/docs/firestore/query-data/listen#detach_a_listener for reference.

Xamarin.Forms - Android Activity with async OnCreate method

I'm running into the questions if it's a problem to mark FormsAppCompatActivity.OnCreate(Bundle bundle) as async? I have to fetch user-specific data from an AWS DynamoDB, and I need to retrieve the user from the Akavache cache before in order to query with the userId. Of course, I could also save the userId to the local settings or serialize the whole user object to be able to retrieve it synchronously.
I also don't expect performance issues during startup because the cache uses SQLite definitely exists. The only problem is that either I await Akavache's GetObject<T>(string key) and therefore, mark everything down to OnCreate as async, or I subscribe to the returned Observable and the following methods will try to query the user data without a valid userId, because the Observable hasn't returned yet.
Since you're using XF for development, the code LoadApplication(new App()); in OnCreate of MainActivity will hook the lifecycle event to App's lifecycle event in PCL.
You didn't post any code, I guess that you place your code for data fetch after LoadApplication(new App());, then as you said it didn't return yet, otherwise the behavior should be different.
I suggest you to call your task in the OnStart() of App in PCL and together use DependencyService to call into your async task for fetching data from PCL.

Resources