Match value of array from database object in Firebase Cloud Functions - javascript

This is my first app project using Google Cloud Functions & Firebase. I'm trying to find away to get a single value of the array that I'm returning and compare it to a set variable and if it matches, update another child's value in that same account.
My App users can add records to the database under their login/user_id that is stored in the database. I'm trying to get a list of the "RecordName" that is a child under that login/user_id that every user has stored in their account.
So basically every "RecordName" in the entire database. When I want to run specials for those records, I need to match the name of that record to the name of the record I have on special and if there is a match, update another child value under that user's account ("special" = true.). This way, when they load their app next time, I have it highlighting that record so they know it's on special.
When I use..
const ref = admin.database().ref(`/store`);
...with the following code...
ref.on('value', function(snapshot) {
// puts ALL items of the object into array using function ..
console.log(snapshotToArray(snapshot));
});
... and the function...
function snapshotToArray(snapshot) {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
var item = childSnapshot.val();
item.key = childSnapshot.key;
returnArr.push(item);
});
return returnArr;
};
... I get the entire array just as it is in the database:
-store
-{ones_users_id}
-recordname: value1
-special: false
-{anothers_users_id}
-recordname: value2
-special: false
ect. ect.
If my record on special is called, "Newbie Record", what would be the best way to take out every individual value for the key: "recordname" from the array, compare each one to var = "Newbie Record" and if they match, update the value of the key: "special" to be true?
I'm new to JSON and NodeJS, I've been searching on here for answers and can't find exactly what I'm looking for. Your feedback would be very helpful.

It sounds like you're looking to query your database for nodes that have "recordname": "Newbie Record" and update them.
An easy way to do this:
const ref = admin.database().ref(`/store`);
const query = ref.orderByChild("recordname").equalTo("Newbie Record");
query.once('value', function(snapshot) {
snapshot.forEach(function(child) {
child.ref.update({ special: true })
});
});
Main differences with your code:
We now use a query to read just the nodes that we want to modify.
We now use once() to read the data only once.
We loop over the children of the snapshot, since a query may result in multiple nodes.
We use the reference of each child and then update its special property.
I recommend reading a bit more about Firebase queries in the documentation.

Related

Currently refactoring my Firestore post data function into an array storage

Currently I have a dashboard application and when a user adds to their dashboard it does a post request to Firestore to set the data in a certain document. Here is what that code looks like:
export function createEntry(data) { // Data has a authorId key with the value of the UID
const userEntry = firestore.collection('userEntries').doc();
userEntry.set(data);
return userEntry;
}
So above, a new entry gets created with a random ID that I then use to grab the data to display later. To get this information later, I loop through all of the entries to see where the authorId matches the user that is log in to return that.
So what I am trying to do is refactor the code so that each document in 'userEntries' is the ID of the user, authorID: UID, and have it be an array where I can keep pushing items into. In return, I can just grab the user array and map over those items to display instead of looping through all my entries and checking.
What I've tried:
export function createEntry(data) {
const userEntry = firestore.collection('userEntries').doc(data.authorId);
userEntry.update({
userData: firebase.firestore.FieldValue.arrayUnion(data)
})
}
So to sum it up, I would like a way to set the document to users ID and push any future entries into their own array, in which I could easily access from the frontend to display.
Hope you can point me in the right direction, thank you!
You don't actually have to revise the original method. If you have the authorId as a field value, you can just query the data using where clause like this:
const uid = auth.currentUser.uid;
firestore.collection().where('authorId', '==', uid).get();
With this method, you are not getting the entire collection and looping through to see which one is written by the user.

How to query the list in a better way using AngularFireDatabase?

"#angular/fire": "^5.2.3",
I am using AngularFireDatabase to manipulate data in firebase. I need to retrieve and update the table below in Firebase. I am currently doing it in the below method. Is there any way which I can use it to query better? Because, I am downloading the entire table and then uploading it again. I don't want to download the entire list of submissions instead just want to push an object to the submission array directly. Thanks in advance.
// Get form submissions for a specific form
getFormSubmissions(key: string) {
this.userSubmissionsList = this.db.list('/form-submissions', ref => ref.orderByChild('formId').equalTo(key));
return this.userSubmissionsList;
}
getSingleFormForSubmission(key: string) {
this.submission = this.db.object('/form-submissions/' + key);
return this.submission;
}
this.formService.getFormSubmissions(this.formId).snapshotChanges().subscribe(response => {
let key = null;
response.forEach(item => {
const a: any = item.payload.toJSON();
key = item.key;
});
this.formService.getSingleFormForSubmission(key).valueChanges().subscribe(resp => {
if (resp.submission === undefined) { resp.submission = []; }
this.formSubs = resp;
});
});
Pushing the data be like:
this.formSubs.submission.push(data);
this.formService.submitUserValues(this.formSubs);
You're storing a JavaScript array in Firebase, which unfortunately means it becomes hard to manipulate. To add an item to an array, you must know how many items already exist in that array, which requires that you first read it.
This is one of the many reasons why the Firebase documentation recommends against using arrays, but instead uses so-called push IDs to add items to lists. From that documentation:
Use the push() method to append data to a list in multiuser applications. The push() method generates a unique key every time a new child is added to the specified Firebase reference. By using these auto-generated keys for each new element in the list, several clients can add children to the same location at the same time without write conflicts. The unique key generated by push() is based on a timestamp, so list items are automatically ordered chronologically.
I also recommend checking out this old-but-still-very-true blog post Best Practices: Arrays in Firebase.

Firebase orderByKey().startAt() not working as expected. What's wrong?

I'm trying to get firebase data from a node which uid must start with a passed string.
I tried a code but I always get the same data. The database data is as following:
And I'm using the following code:
var ref = firebase.database().ref("restaurantes/history");
ref.orderByKey().startAt(userUID).once("child_added", function(snapshot) {
snapshot.forEach(child => {
if(child.key == "orders")
{
console.log(child.val());
_.each(child.val(), (value, key) => {
arrtmp.push(value)
})
}
})
If user is "FKQLlqa" I should get the history data shown in the picture. If I user is "abc" I shouldn't get any data. But I always get the data shown in the picture. Should I use another way of querying? Or I should use a key field inside orders and payments data?
Regards!
Try the following:
var ref = firebase.database().ref("restaurantes/history");
ref.child(userUID).once("value", function(snapshot) {
if (snapshot.exists()) {
console.log(snapshot.val());
}
else {
console.log("different user");
});
This will check if the snapshot that contains the userId (added as a parameter in the child() method), already exists in the database then you will be able to retrieve the data under the userId.
For reference:
https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#exists
Peter's answer is the correct solution. I'm merely adding this for completeness.
When you call orderBy... on a Firebase reference, the database orders all child nodes on the key/value/child that you specify.
If you then subsequently call startAt(...) on the query, it finds the (first) node that starts with that value and starts returning all results from there. So if you start at FKQLlqa, it will start returning keys at FKQLlqa and then return all keys after it.
If you want to return the child node(s) with a specific key/value/child, you'd use equalTo(...). So:
ref.orderByKey().equalTo(userUID).once("child_added", function(snapshot) {
...
But as Peter said already, this is just a more expensive way to look up a child with a known key. I highly recommend using his better approach: ref.child(userUID).once("value".

JavaScript Firebase: Query Snapshot Always Null

No matter what I do I can't seem to figure out a way to access the child "onSite", which shows as being there when I log snapshot.val(), but I cannot figure out how to access it.
Code:
firebase.database().ref().child("users").orderByChild('facebook_id').equalTo(fbID).once("value").then(function(snapshot) {
console.log(snapshot.val());
console.log(snapshot.child("onSite").val());
});
Here is the response:
It shouldn't be null, it should be false. I can't do child("4mUUjF...").child("onSite").val() because I don't know what the ID is before the query. Using an each loop doesn't work, it only loops through the first level, which is the ID.
Use the key of the object
Get the snapshot val and then find the key with the Object.keys method. This will allow you to then get inside the snap. Once there it's a simple matter of accessing the values like any other object.
firebase.database().ref().child("users").orderByChild('facebook_id').equalTo(fbID).once("value").then(function(snapshot) {
let snap = snapshot.val();
let key = Object.keys(snap)[0]
console.log(snap[key].onSite);
})
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
Your code needs to handle the list, by using Snapshot.forEach():
firebase.database().ref().child("users").orderByChild('facebook_id').equalTo(fbID)
.once("value").then(function(result) {
result.forEach(function(snapshot) {
console.log(snapshot.val());
console.log(snapshot.child("onSite").val());
});
});

firebase database store list of items

HERE IS MY CODE
//1. Add menu items to the globalMenu and to restaurant, and the restaurantId of the restaurant adding menu.
this.writeNewMenuItem = function(itemName, restaurantId) {
// A post entry.
var menuItem = {
itemName: [itemName]
};
var ref = firebase.database().ref();
// Get a key for a new Post.
var newItem = ref
.child('globalMenu')
.push(menuItem);
ref
.child('restaurants')
.child(restaurantId)
//.child(newItem.key)
.update(menuItem);
}
Also let me know the way we can push and pop these items.
and if duplicate found this should not insert.
I want to fetch matched characters items, like if I pass 'app' in query this should return 'apple, application, appengine' etc. How could I do this?
You should try to avoid "arrays" in a Firebase Database, because:
... for distributed data, they aren't reliable because they lack a unique, permanent way to access each record.
https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html
Regarding your third question: querying the the database this way is not possible, you need to receive the whole list of all child nodes and do the filtering on the client side. I could recommend reading best practices for structuring the data: https://firebase.google.com/docs/database/admin/structure-data

Categories