Add field to document using cloud functions - javascript

I wanted to make the id of each document as a field of that document so that I can store it inside the doc. here is the cloud function I created:
exports.assignPID = functions.database
.ref('/players/{playerId}')
.onCreate((snapshot,context)=>{
const playerId = context.params.playerId;
console.log("new player "+playerId);
// const data = snapshot.val();
return snapshot.ref.update({'pid': playerId})
})
this deploys without any errors but whenever I add a new document to the 'players' collection there is no change in the document whatsoever

In your question, you use the word "document" to describe your data, which is a Firestore concept, and you've tagged this question google-cloud-firestore. However, the code you've written is for Realtime Database, which is a completely different product. So it will never run in response to changes in Firestore.
When you declare a function with functions.database, that's means Realtime Database. Instead, you should declare a Firestore trigger with functions.firestore. Please read the linked documentation for information about how to do that.

Related

Firestore - Skip document update if it doesn't exists, without need of failures

I have a collection
/userFeed
Where I create/delete docs (representing users) when the current user starts following/unfollowing them.
...
/userFeed (C)
/some-followed-user (D)
-date <timestamp>
-interactions <number>
When the user likes a post, the interactions field will be updated. But... what if the user doesn't follow the post owner? Then, I will just need to skip the document update, without necessity of producing failures/errors.
const currentUserFeedRef = firestore
.collection("feeds")
.doc(currentUserId)
.collection("userFeed")
.doc(otherUserId);
const data = {
totalInteractions: admin.firestore.FieldValue.increment(value),
};
const precondition = {
exists: false, // I am trying weird things
};
if (batchOrTransaction) {
return batchOrTransaction.update(
currentUserFeedRef,
data,
precondition
);
}
Is it possible to just "skip the update if the doc doesn't exist"?
Is it possible to just "skip the update if the doc doesn't exist"?
No, not in the way that you're explaining it. Firestore updates don't silently fail.
If you need to know if a document exists before updating it, you should simply read it first and check that it exists. You can do this very easily in a transaction, and you can be sure that the update won't fail due to the document being missing if you check it this way first using the transaction object.
In fact, what you are trying to do is illustrated as the very first example in the documentation.

Trigger cloud function on sub-collections update

I know that this question is already asked but it didn't help.
I have a "chats" collection with one document "members" and a sub-collection "messages" and I would like to trigger a cloud function when a new message is added in the sub-collection.
This is what I tried but it is only triggered when "members" is updated, and does not have any information on the sub-collection:
exports.chatsCollectionTriggers = functions.firestore.document('/chats/{chatId}/messages/{messageId}').onUpdate(async (change, context) => {
let chatBefore = change.before.data();
let chatAfter = change.after.data();
console.log(JSON.stringify(chatBefore, null, 2));
console.log(JSON.stringify(chatAfter, null, 2));
console.log(context.params.chatId);
console.log(context.params.messageId);});
My firestore collection :
My question is how can I trigger a cloud function on a sub-collection update ?
Your Cloud Function will not be triggered when you modify a document of the chats collection (e.g. if you modify the members field of the G162R... document).
Your Cloud Function will be triggered when you modify (not when you create) a document in the messages subcollection of a document in the chats collection. For example, if you change the value of the text field of the message document vVwQXt.....
So, to answer to your question
My question is how can I trigger a cloud function on a sub-collection
update
If by "sub-collection update" you mean the update of an existing document in a subcollection, your Cloud Function is correct.
If by "sub-collection update" you mean the creation of a new document in a subcollection (which can be one interpretation of "a sub-collection update"), you should change your trigger type from onUpdate() to onCreate().
From the following sentence in your question, i.e. "I would like to trigger a cloud function when a new message is added in the sub-collection", it seems you want to go for the second case, so you should adapt you Cloud Function as follows:
exports.chatsCollectionTriggers = functions.firestore.document('/chats/{chatId}/messages/{messageId}').onCreate(async (snap, context) => {
const newValue = snap.data();
console.log(newValue);
console.log(context.params.chatId);
console.log(context.params.messageId);
return null; // Important, see https://firebase.google.com/docs/functions/terminate-functions
})
More details in the doc.

Firebase Realtime Databse difference between data snapshots

If I have a database structure like here and I make a query as shown below.Is there a difference on the traffic used to download the snapshot from the database if I access each node with snapshot.forEach(function(childSnapshot) and if I don't access the nodes?
If there is no difference, is there a way to access only the keys in Chats without getting a snapshot data for what each key contains.I'm assuming that this way it will generate less downloaded data
var requests = db.ref("Chats");
requests.on('child_added', function(snapshot) {
var communicationId = snapshot.key;
console.log("Chat id = " + communicationId);
getMessageInfo(
communicationId,
function() {
snapshot.ref.remove();
}
);
When you call requests.on('child_added', ...), you are always going to access all of the data at the requests node. It doesn't matter what you do in the callback function. The entire node is loaded into memory, and cost of the query is paid. What you do with the snapshot in memory doesn't cost anything else.
If you don't want all of the child nodes under requests, you should find some way to filter the query for only the children you need.
As they mentioned in the documentation, either of these methods can be used:
Call a method to get the data.
Set a listener to receive data-change
events.
Traffic depends upon our usage. When your data need not get updated in realtime, you can just call a method to get the data (1) But if you want your data to be updated in realtime, then you should go for (2). When you set a listener, Firebase sends your listener an initial snapshot of the data, and then another snapshot each time the child changes.
(1) - Example
firebase.database().ref('/users/').once('value') // Single Call
(2) - Example
firebase.database().ref('/users/').on('child_added') // Every Update It is Called
And also, I think you cannot get all keys, because when you reference a child and retrieve a data, firebase itself sends it as key-value pairs (DataSnapshot).
Further Reference: https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot
https://firebase.google.com/docs/database/web/read-and-write

how to query from update handler javascript code

What I'm trying to do:
I want to add data (id, data) to db. While doing so, I want to check if the id already exists and if so, append to existing data. else add a new (id, data) entry.
Ex: This could be a db of student id and grades in multiple tests. If an id exists in the db already, I want to just append to the existing test scores already in db, else create a new entry: (id, grades)
I have setup an update handler function to do this. I understand, couchdb insert by default does not do the above. Now - how do I check the db for that id and if so, decide to whether to add a new entry or append. I know there is db.get(). However, I presume since the update handler function is already part of the db itelf, there may be a more efficient way of doing it.
I see this sample code in the couchdb wiki:
function(doc, req){
if (!doc){
if ('id' in req && req['id']){
// create new document
return [req, 'New Document'];
}
// change nothing in database
return [null, 'Incorrect data format'];
}
doc[id] = req;
return [doc, 'Edited World!'];
}
a few clarifications in this example that's not clear: where do we get the id from? Often the id is not explicitly passed in while adding to db.
Does that mean, we need to explicitly pass a field called "_id"?
how do I check the db for that id and if so, decide to whether to add a new entry or append.
CouchDB does this for you, assuming HTTP client triggers your update function using the ID. As the documentation describes:
When the request to an update handler includes a document ID in the URL, the server will provide the function with the most recent version of that document
In the sample code you found, the update function looks like function(doc, req) and so in the code inside of that function the variable doc will have the existing document already "inside" your CouchDB database. All the incoming data from the client/user will be found somewhere within req.
So for your case it might look something like:
function(doc, req){
if (doc) {
doc.grades.push(req.form.the_grade);
return [doc, "Added the grade to existing document"];
} else {
var newDoc = {_id:req.uuid, grades:[req.form.the_grade]};
return [newDoc, "Created new document ("+newDoc._id+") for the grade"];
}
}
If the client does a POST to /your_db/_design/your_ddoc/_update/your_update_function/existing_doc_id then the first part of the if (doc) will be triggered, since you will have gotten the existing document (pre-fetched for you) in the doc variable. If the client does a POST to just /your_db/_design/your_ddoc/_update/your_update_function, then there is no doc provided and you must create a new one (else clause).
Note that the client will need to know the ID to update an existing document. Either track it, look it up, or — if you must and understand the drawbacks — make them determinate based on something that is known.
Aside: the db.get() you mentioned is probably from a CouchDB HTTP client library and is not availble (and would not work) in the context of any update/show/list/etc. functions that are running sandboxed in the database "itself".
Cited from the documentation:
If you are updating an existing document, it should already have an _id set, and if you are creating a new document, make sure to set its _id to something, either generated based on the input or the req.uuid provided. The second element is the response that will be sent back to the caller.
So tl;dr, if the _id is not specified, use req.uuid.
Documentation link: http://docs.couchdb.org/en/stable/ddocs/ddocs.html#update-functions

Issue pulling data from the firebase realtime database with child_added in javascript

I am having trouble retrieving posts from the firebase realtime database with javascript:
var postsRef = database.ref().child('posts');
postsRef.on('child_added', postData => {
console.log(postData.val().title, postData.val().content,
postData.val().author);
addPostElement(postData.val().title, postData.val().content, postData.val().author);
});
That is exactly what is said in the documentation, but it never runs, even though (the child_added event) should be triggered once for every post
try setting postsRef to database.ref('posts') also cloud functions has a cleaner api for listening to this type of events its worth giving it a look

Categories

Resources