How to get firebase pushID in onwrite event? - javascript

How to get the push ID?
I have a JSON which looks like this:
purchaseTransaction: {
xxxxxx: {
amount: 1000,
user: yyyyyyy
}
}
and when this purchaseTransaction document is updated, I would like to get the pushID (this is generated by firebase)?
exports.addPurchaseTransactionToUser = functions.database.ref('/purchaseTransaction/{pushId}').onWrite((change, context) => {
const snapshot = change.after;
const val = snapshot.val();
console.log('val',val);
// How to get the pushID?
});

From the documentation on handling event data:
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onCreate((snapshot, context) => {
// Grab the current value of what was written to the Realtime Database.
const original = snapshot.val();
console.log('Uppercasing', context.params.pushId, original);
So in your case the push ID will be available as context.params.pushId.

For your code, use context.params.pushId.

Related

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.

Undefined username in cloud functions?

I want to send a notification to a specific device so I write this function and its work right but I got undefined in the username
Logs output:
Get this
after: { '-LhjfwZeu0Ryr6jYRq5r': { Price: '888', date: '2019-6-19', description: 'Ghh', id: 50, nameOfProblem: 'Vbh', providerName: 'Loy', providerService: 'Carpenter', statusInfo: 'Incomplete', time: '15:22', username:"devas" }}
And the username is undefined
Here is the function
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders')
.onWrite(async (snapshot, context) => {
const registrationTokens = "------";
const providerId = context.params.pid;
const userId = context.params.uid;
const event = context.params;
console.log("event", event);
console.log(`New Order from ${userId} to ${providerId}`);
const afterData = snapshot.after.val(); // data after the write
const username = snapshot.after.val().username;
console.log(afterData);
console.log(username);
const payload = {
notification: {
title: 'Message received',
body: `You received a new order from ${username} check it now! `,
sound: "default",
icon: "default",
}
};
try {
const response = await admin.messaging().sendToDevice(registrationTokens, payload);
console.log('Successfully sent message:', response);
}
catch (error) {
console.log('Error sending message:', error);
}
return null;
});
It looks like the code you wrote is meant to run when a new order is added to the database. But you've declared it to trigger like this:
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders')
.onWrite(async (snapshot, context) => {
This means that the code instead triggers whenever anything is written under the orders node for a user. To trigger only when an order is written under that orders node, define your trigger as:
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders/{orderid}')
.onWrite(async (snapshot, context) => {
The difference above is that the path now includes {orderid} meaning that it triggers one level lower in the tree, and your snapshot.after will no longer contain the -L level.
Since you actually only seem to care about when an order gets created, you can also only trigger on that (meaning your function won't get called when an order gets updated or deleted). That'd be something like this:
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders/{orderid}')
.onCreate(async (snapshot, context) => {
...
const afterData = snapshot.val();
const username = snapshot.val().username;
console.log(afterData);
console.log(username);
...
});
Here we again trigger on the lower-level in the JSON. But since we now trigger onCreate, we no longer have a before and after snapshot, and instead just do snapshot.val() to get the data that was just created.
Since the object you are retrieving has a generated member you could use a for-in loop to retrieve the value.
const object = snapshot.after.val()
for(const key in object) {
if (object.hasOwnProperty(key)) {
const element = object[key];
if(element.username) {
console.log(element.username);
break;
}
}
}

How to if check data in real-time-db FIREBASE

I would like to check/compare if a value is inside this data:
example:
const uid = '35nv594aotgcv'
#check if uid is inside
firebase
.database()
.ref('followers/2mvouwB0E0aEN5MnAhOLWaHiu6b2')
.once("value", snapshot => {
if (snapshot.exists()) {
const data = snapshot.val(); // data are the other two uid's in the image above
}
});
So how can I check if the const uid = '35nv594aotgcv' is inside the snapshot data?
or if I have an Array with uid's like const uids = ['234', '343', '3242', ...]
If I understand you correctly, you're looking for DataSnapshot.hasChild(). With that you can check whether the snapshot has a certain child node.
Something like:
firebase
.database()
.ref('followers/2mvouwB0E0aEN5MnAhOLWaHiu6b2')
.once("value", snapshot => {
if (snapshot.hasChild('35nv594aotgcv')) {
console.log('Yes');
}
});

How to update a single firebase firestore document

After authenticating i'm trying to lookup a user document at /users/, then i'd like to update the document with data from auth object as well some custom user properties. But I'm getting an error that the update method doesn't exist. Is there a way to update a single document? All the firestore doc examples assume you have the actual doc id, and they don't have any examples querying with a where clause.
firebase.firestore().collection("users").where("uid", "==", payload.uid)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
doc.update({foo: "bar"})
});
})
You can precisely do as follows (https://firebase.google.com/docs/reference/js/v8/firebase.firestore.DocumentReference):
// firebase v8
var db = firebase.firestore();
db.collection("users").doc(doc.id).update({foo: "bar"});
//firebase v9
const db = getFirestore();
async (e) => { //...
await updateDoc(doc(db, "users", doc.id), {
foo: 'bar'
});
//....
check out the official documentation as well
Check if the user is already there then simply .update, or .set if not:
var docRef = firebase.firestore().collection("users").doc(firebase.auth().currentUser.uid);
var o = {};
docRef.get().then(function(thisDoc) {
if (thisDoc.exists) {
//user is already there, write only last login
o.lastLoginDate = Date.now();
docRef.update(o);
}
else {
//new user
o.displayName = firebase.auth().currentUser.displayName;
o.accountCreatedDate = Date.now();
o.lastLoginDate = Date.now();
// Send it
docRef.set(o);
}
toast("Welcome " + firebase.auth().currentUser.displayName);
});
}).catch(function(error) {
toast(error.message);
});
-- UPDATE FOR FIREBASE V9 --
In the newer version of Firebase this is done like this:
import { doc, updateDoc } from "firebase/firestore";
const washingtonRef = doc(db, "cities", "DC");
// Set the "capital" field of the city 'DC'
await updateDoc(washingtonRef, {
capital: true
});
in your original code changing this line
doc.update({foo: "bar"})
to this
doc.ref.update({foo: "bar"})
should work
but a better way is to use batch write:
https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes
correct way to do this is as follows;
to do any data manipulation in snapshot object we have to reference the .ref
attribute
firebase.firestore().collection("users").where("uid", "==", payload.uid)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
doc.ref.update({foo: "bar"})//not doc.update({foo: "bar"})
});
})
You only need to found official ID of document, code here!
enter code here
//Get user mail (logined)
val db = FirebaseFirestore.getInstance()
val user = Firebase.auth.currentUser
val mail = user?.email.toString()
//do update
val update = db.collection("spending").addSnapshotListener { snapshot, e ->
val doc = snapshot?.documents
doc?.forEach {
//Assign data that I got from document (I neet to declare dataclass)
val spendData= it.toObject(SpendDt::class.java)
if (spendData?.mail == mail) {
//Get document ID
val userId = it.id
//Select collection
val sfDocRef = db.collection("spendDocument").document(userId)
//Do transaction
db.runTransaction { transaction ->
val despesaConsum = hashMapOf(
"medalHalfYear" to true,
)
//SetOption.merege() is for an existing document
transaction.set(sfDocRef, despesaConsum, SetOptions.merge())
}
}
}
}
}
data class SpendDt(
var oilMoney: Map<String, Double> = mapOf(),
var mail: String = "",
var medalHalfYear: Boolean = false
)

Firebase Functions: Cannot read property 'val' of undefined

I'm trying to add a Function in my Firebase Database, that creates/updates a combined property of two others, whenever they change.
The model is like this:
database/
sessions/
id/
day = "1"
room = "A100"
day_room = "1_A100"
And my function so far:
exports.combineOnDayChange = functions.database
.ref('/sessions/{sessionId}/day')
.onWrite(event => {
if (!event.data.exists()) {
return;
}
const day = event.data.val();
const room = event.data.ref.parent.child('room').data.val();
console.log(`Day: ${day}, Room: ${room}`)
return event.data.ref.parent.child("day_room").set(`${day}_${room}`)
});
exports.combineOnRoomChange = functions.database
.ref('/sessions/{sessionId}/room')
.onWrite(event => {
if (!event.data.exists()) {
return;
}
const room = event.data.val();
const day = event.data.ref.parent.child('day').data.val();
console.log(`Day: ${day}, Room: ${room}`)
return event.data.ref.parent.child("day_room").set(`${day}_${room}`)
});
But it's throwing this error:
TypeError: Cannot read property 'val' of undefined
I'm following the very first example in the Firebase Functions Get Started (Add the makeUppercase() function) and this is what it does in order to reach the entity reference:
event.data.ref.parent
Am I using the child() function wrongly? Any ideas?
When Cloud Functions triggers your code, it passes in a snapshot of the data that triggered the change.
In your code:
exports.combineOnDayChange = functions.database
.ref('/sessions/{sessionId}/day')
This means you event.data has the data for /sessions/{sessionId}/day. It does not contain any data from higher in the tree.
So when you call event.data.ref.parent, this points to a location in the database for which the data hasn't been loaded yet. If you want to load the additional data, you'll have to load it explicitly in your code:
exports.combineOnDayChange = functions.database
.ref('/sessions/{sessionId}/day')
.onWrite(event => {
if (!event.data.exists()) {
return;
}
const day = event.data.val();
const roomRef = event.data.ref.parent.child('room');
return roomRef.once("value").then(function(snapshot) {
const room = snapshot.val();
console.log(`Day: ${day}, Room: ${room}`)
return event.data.ref.parent.child("day_room").set(`${day}_${room}`)
});
});
Alternatively, consider triggering higher in your tree /sessions/{sessionId}. Doing so means that you get all the necessary data in event.data already, and also means you only need a single function:
exports.updateSyntheticSessionProperties = functions.database
.ref('/sessions/{sessionId}')
.onWrite(event => {
if (!event.data.exists()) {
return; // the session was deleted
}
const session = event.data.val();
const day_room = `${session.day}_${session.room}`;
if (day_room !== session.day_room) {
return event.data.ref.parent.child("day_room").set(`${day}_${room}`)
});
});

Categories

Resources