Cloud Functions retrieve List from Firebase Database - firebase

I'm triggering a Cloud Function using Http Request.
The issue is to retrieve the entire List of Objects I have, without an event to then loop through them.
The List is under the account/userId Node.
Here is what I use but I get nothing:
return admin.database().ref('/account/' + userId).once('value').then(function (snap) {
let data = snap.val();
}

Without seeing your database structure it is a bit difficult to write an answer and be 100% sure it is a correct one, but the following should do the trick:
return admin.database().ref('/account/' + userId).once('value').then(function (snap)
snap.forEach(function(child) {
const childKey = child.key; // <- here you get the key of each child of the '/account/' + userId node
console.log(childKey);
const childVal = child.val(); // <- and here you get the values of these children as JavaScript objects
console.log(childVal);
});
});
In case this is not exactly what you are looking for, please update you Question with your database structure and the entire code of your Cloud Function.

Related

How do i query a Firebase database for a nested property?

Hi i have a noSql db in firebase.
I want to get the object where userId is 288
i'v tried many combinations but i cant figure out how its done.
This is my code so far :
var refTest= database.ref('conversation')
var query = refTest
.orderByChild('messages');
query.on('value', function(data) {
var a = data.val();
console.log(a.messages.userId);
console.log(data.val());
});
This is a image of my "schema"
I'm obviously a noob when it comes to NoSQL. I do understand SQL
All help is appreciated
You can order/filter on a nested value like this:
var refTest= database.ref('conversation')
var query = refTest.orderByChild('messages/userId').equalTo("288");
query.on('value', function(snapshot) {
snapshot.forEach(function(child) {
console.log(child.key);
console.log(child.val());
});
});
The forEach is needed, since there may be multiple child nodes with messages/userId equal to 288.
The key named "messages" doesn't make sense in your schema. Because if you want to have another message under that conversation, then you wouldn't be able to add it with the same key name and you also couldn't add it under "messages" because it would overwrite the other one. My suggestion is to use the push() method for adding a new message. This way you uniquely identify each message.
Regarding your question, an easy to understand way of parsing your schema is this: you loop through each message of each conversation for finding the messages with userID.
refTest.on('value', function(data) {
var conversations = data.val();
for (conversation in conversations){
for (message in conversation) {
if (message.userId == 288) {
// do whatever you need
// and eventually return something to break the loops
}
}
}
}
Of course, you can adapt it based on your needs

Firebase "child_added" event

I want a function to be called whenever a new child is added to "chat". I know this can be done using "child_added" event. However, from that function, I want to modify the newly created child.
So suppose a new child "123456" is added to chat and I want to update the "123456" object in the DB. I think I could solve the problem if I somehow manage to get the key (in this case it's 123456) of the newly added object. Is there a way to achieve this?
That should do the trick:
ref.on('child_added', function(childSnapshot, prevChildKey) {
var key = childSnapshot.key;
...
});
You will find more info at:
https://firebase.google.com/docs/reference/js/firebase.database.Query#on
u can also use firebase cloud functions as well by putting a trigger, so that this can be handled by server.
export const onNewChatTrigger = functions.database.ref('chat/{chatId}').onCreate(event => {
let key = event.params.chatId;
let data = event.data.val();
...
});

Firebase function access not related data [duplicate]

This question already has an answer here:
How to read any data from database on its write trigger on one of its child in firebase functions?
(1 answer)
Closed 5 years ago.
I'm searching for a way when I can access database elements not related to my trigger data in firebase functions.
As I see I can set(...) things on other elements but unfortunately I can't just read the values out of the elements, for example this doesn't work:
event.data.adminRef.root.child('bettings/'+matchId+'/begin_at').val()
I know about the 'proper way' to get those things, which is like:
var match = event.data.adminRef.root.child('bettings/' + matchId + '/begin_at');
match.once('value',function(snapshot){
var alma = snapshot.val();
console.log('alma val');
console.log(alma);
});
But I hope there is a better/easier way then write such codes all the time I need something out of my current scope.
Update: it is not a duplicate of How to read any data from database on its write trigger on one of its child in firebase functions? !
I know about ....once(..), and that I can access the values through promises but I need a much more quicker way, because sometimes it takes about 10 seconds, which is really slow and the user won't get the response in time!
Here is an example where you access data from a specific database node and perform a task with the value jobowner:
let jobRef = admin.database().ref(`/jobs/${jobid}`);
const jo = jobRef.child("owner").once('value');
return Promise.all([jo]).then(r => {
const jobowner = r[0];
const promises = [];
let key = admin.database().ref(`/jobowners/${jobowner}`).set({
value: 'test',
other: false
});
promises.push(room);
return Promise.all(promises);
});

Cloud Functions database event always contains empty data

I have an issue with my cloud functions where in all my database events all return empty. For example, in the following event the event.data.val() would return null. I am doing an update operation and have tested the update by testing the cloud function using the shell as well as after deploying.
export const createSubscription = functions.database.ref('/users/{userId}/subscription').onWrite( event => {
if(!event.data.val()) {
return;
}
});
But I can easily hook into the auth.user() events like the following and receive the data.
export const createStripeUser = functions.auth.user().onCreate(event => {
const user = event.data;
});
Edit: Passing data into the collection for example like the one below on the emulator console
createSubscription({
testKey: 'testValue'
})
or the following on from my frontend
db.ref(`/users/23213213213/subscription`).update({ testKey: 'testValue'});
would return null on the function.
DougStevenson is correct. For the .onCreate() you would be doing it correct wit a myDatabaseFunction('new_data').
With the .onWrite() you need to pass in the before and after like my example below.
You may have got stuck were I did. Note that I have a curly bracket around the before and after the final JSON. It didn't work properly without them.
addComment({before: {"comment":"before comment","role":"guest"}, after:{"comment":"After Comment","role":"guest"}})
Hope my example helps a bit more than a generic string parameter.
Good Luck!

Good way to delete all data according to criteria/child's value in Firebase database admin?

I want to clean up this userPublic by deleting all of its child node which has isTesting == true. I am using Firebase's cloud function. My approach would be :
const userPublic = admin.database().ref("/userPublic")
const testsInUserPublic = userPublic.orderByChild("isTesting").equalTo(true)
testsInUserPublic.once("value", dataSnapshot => {
// ???
})
Since I can only call .remove() on reference and not snapshot but to filter the child I want it returns snapshot, how can I get the reference from snapshot? (I would like to know the key XXX-XXX-XXX of each filtered child, so I can concatenate with userPublic and .remove() them one by one)
Also, even if I can get all the references that I want to remove I think deleting them one by one by calling .remove() then wait for promise, then call the next one does not sounds like an optimal way. Are there any way to remove all of them in one go?
If it involves calling .update() on the top userPublic node, I would have to fetch everything, remove the one with isTesting and then put the remaining back for update. This sounds like it is not efficient compared to the filtering way. As eventually the one with .isTesting is only about 5% of all data. Or is this actually the approach everyone is using?
You're almost there. All that's left is to create a single multi-location update from the results of your query:
const userPublic = admin.database().ref("/userPublic")
const testsInUserPublic = userPublic.orderByChild("isTesting").equalTo(true)
testsInUserPublic.once("value", snapshot => {
var updates = {};
snapshot.forEach(function(child) {
updates["/userPublic/"+child.key] = null;
});
userPublic.update(updates);
})
Doing this with promises would not be too different:
testsInUserPublic.once("value", snapshot => {
var promises = [];
snapshot.forEach(function(child) {
promises.push(child.ref.remove());
});
Promise.all(promises); // this returns a promise that resolves once all deletes are done, or that rejects once one of them fails
})
Performance of this will be very similar, since Firebase pipelines the requests over a single connection. See http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786

Resources