Firebase documentation on structuring the database mentions the following:
...when you fetch data at a location in your database, you also retrieve all of its child nodes.
I have the following basic data structure:
databaseRoot: {
orders: {
order1: {
firebaseId: firebaseUid,
...
}
}
orderItems: {
order1: {
firebaseId: firebaseUid,
...
}
}
}
In my android start-up code I intend to sync the orders and orderItems that belong to the current user to handle the offline scenario.
FirebaseDatabase.getReference("orders").orderByChild("firebaseId").equalTo(firebaseUser.uid).keepSynced(true)
FirebaseDatabase.getReference("orderItems").orderByChild("firebaseId").equalTo(firebaseUser.uid).keepSynced(true)
My Question:
Do the sync references consider the data location to be the entire Orders and OrderItems nodes, respectively? Or does it resolve down to the specific child nodes that satisfy the firebase user id equal to the current user?
My hope is for the latter to be the result, as the client does not need any records beyond those belonging to the current user.
Calling keepSynced(true) on a location is essentially the same as keeping a listener with an empty callback on that location.
So these two commands will ensure you that the orders and orderItems for the specific user are in cache.
But if that is the type of behavior you want, you might want to consider keep the data in a simpler structure: /orders/firebaseUid/order1, /orders/firebaseUid/order2, etc. With this structure you won't need a query to get the orders for a user and can just read from (and call keepSynced() on) /orders/firebaseUid.
Related
So suppose I am building an app that lets users manage trips. When a trip is created , any number of users can be added in it. I want this data to be stored in a single place and then for each user be able to retrieve the trips that that person is included in. My data looks like this:
-trips
-<trip-id>
-title
-budget
-etc
-people
-<person-id>
-name
-uid
-<person-id>
-name
-uid
-<trip-id>
-
-
-
This trip will contain all the trips created by all the users. To show any person their trips, I want to retrieve only the lists that person exists in.
This is what I've tried to do including other similar approaches.
rootReference.child("trips").orderByChild("uid").equalTo(FirebaseAuth.instance.currentUser.uid).addValueEventListener(object:ValueEventListener){
override fun onDataChange(snapshot: DataSnapshot) {
//this should only return the trips that current user exists in.
}
}
I have checked the documentation for searching and filtering on firebase but there is nothing that show filtering based nested keys. One particular example is this. I understand it perfectly. If for example I try to filter my trips based on the main attributes like title, budget, it works, but not when I use an attribute of a nested child.
What other approach can I use to filter based to nested keys or should I structure the data differently? Any help is greatly appreciated.
Firebase Realtime Database queries operate on a flat list of child nodes directly under the path that you query.
So the value you order/filter on has to be at a fixex path under each immediate child node. Since that isn't the case for your uid, you can't query across all trips for the UID of all users of those trips.
You can query across one trip for a UID of a user (and then get back that user), or you can query across all trips for properties of the trip itself, such as its title or budget.
If you want to query across all users on all trips, consider keeping an additional list where you have the UID of the user as the key, and then all their trips under there:
"user_trips": {
"uid1": {
"tripid1": true,
"tripid2": true
},
"uid2": {
"tripid2": true,
"tripid3": true
}
}
Also see:
Firebase Query Double Nested
Firebase query if child of child contains a value
Many to Many relationship in Firebase
This question already has an answer here:
Firebase query if child of child contains a value
(1 answer)
Closed 3 years ago.
I need a firebase query to filter the list based on the value of an array.
if any of the index of GID(Array) contains the given key. e.g my key is YsGMyfLSGRNHxDWQmhpuPRqtxlq1 and one node's GID have that on 0th index and other have that on 1st index. So these two lists need to be returned.
Currently, I can only get the one at 0th index using the code
//userID = YsGMyfLSGRNHxDWQmhpuPRqtxlq1
firebaseDatabase.child("Groups").queryOrdered(byChild: "GID/0").queryEqual(toValue:userID)
When I try to combine the query I am getting errors.
I don't know about your database structure, But I can explain that There is a limitation in Firebase Realtime database that you can only order by 1 child.
So now if we require to order by 2 Childs we can combine 2 nodes and make it 1 node and can apply order by query on it. For example
If we have username & email fields we can make a new field username_email and can apply order by on it.
Like
user: {
username: "john",
email: "john#g.com"
username_email = "john_john#g.com"
}
Now we can write
firebaseDatabase.child("user").queryOrdered(byChild: "username_email").queryEqual(toValue: "john_john#g.com");
There is no way you can filter your groups based on a value that exist within an array. If you want to query your database to get all groups a particular user is apart of, then you should consider augmenting your data structure to allow a reverse lookup. This means that you should add under each user object the groups in which that user is present.
This means that you'll need to duplicate some data, but this is not a problem when it comes to Firebase. This is a quite common practice, which is named denormalization and for that, I recommend you see this video, Denormalization is normal with the Firebase Database.
When you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.
However, what you need is actually allowed in Cloud Firestore. Its array-contains operator allow you to filter documents that have a certain value in an array. For more on this topic, please see the following post:
Better Arrays in Cloud Firestore.
Let's say my current structure firebase realtime database:
{
chatRooms:{
chat1:{
participants:{
user1-id:true,
user2-id:true
}
participantsCount:2,
lastTimeUpdated: {TIMESTAMP},
chatRoomName:"A chatroom",
maxParticipantsCount:10
}
}
users:{
user1-id:{
name:user1-name,
email:user1-email
}
user2-id:{
name:user2-name,
email:user2-email
}
}
}
I need to display all chatrooms that contains a specific user along with all its information, and my solution now is:
#userId is currently authenticated, firebase user.
ref.child("chats").orderByChild("/participants/"+userId).equalTo(true)
which returns the list of chats containing $userId which equals to true, along with additional information to display to the user. Is there any possible way to change this query AND/OR database structure to support optimal indexing? If I wanted to add indices, it would be something like:
chatrooms:{
participants:{
indexOn:"user1-id","user2-id"
# number of ids grows as participants increase
# Not only that, I will have to add one by one manually.
}
}
How can I add indices and also at the same time do a query in Android that will display all chatrooms that a user belongs to along with their information?
AFAIK, I cannot "loop" over the keys of the child in Android
To loop over the children of a snapshot in Android do:
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
System.out.println(childSnapshot.getKey());
}
Relevant section in the docs: https://firebase.google.com/docs/database/android/lists-of-data#listen_for_value_events
If you're asking how to display the information about each chat room that a user is in, that will take a client-side join like this:
firebase.database().ref("userChatrooms").child(firebase.auth().currentUser.uid).once(function(roomsSnapshot) {
roomsSnapshot.forEach(function(roomKey) {
firebase.database().ref("chatrooms").child(roomKey.key).once(function(roomSnapshot) {
console.log(roomSnapshot.child("name").val());
})
})
})
This type of client-side join is not nearly as slow as most developers expect, since Firebase pipelines the nested requests.
How can i get All chats where Users contains a specific Uid
Query sItemQuery = mDatabase.getReference().child("chats").limitToLast(200);
FirebaseRecyclerOptions<ChatMetaData> options =
new FirebaseRecyclerOptions.Builder<ChatMetaData>()
.setQuery(sItemQuery, ChatMetaData.class)
.setLifecycleOwner(this)
.build();
You can't query across multiple levels like that. See Firebase Query Double Nested
So while your current data structure makes it easy to find the current users in a chat, it doesn't make it easy to find the current chats for a user.
For that you'll need to add an additional data structure. Something like:
user_chats: {
uid1: {
chatid1: true,
chatid2: true
}
uid2: {
chatid2: true,
chatid3: true
}
}
With this additional structure, you can easily find the chats for the current user by reading /user_chats/$uid.
Also see:
Firebase query if child of child contains a value
Is there any way to select specific properties from firebase Realtime Database? I know there is a way to retrieve selected properties from firestore but how can get via Realtime database using Node.js
I want only Notes from everyone nothing else.
Suppose i just want to select Notes from Allergy here is my sample code which i tried but not successes...
admin.database().ref(`vitals/Allergy`).select('Notes').then(result => {//here is my result.....})
But it shows me that select is not a function.......
Realtime Database doesn't support "projections" like this (neither does Cloud Firestore). If you are going to query across multiple child nodes, you are going to get each entire child node that matches the query. Even if you want just one property of each child, you can't avoid the cost of downloading the entire child.
If your app is very sensitive to performance on these types of queries, consider duplicating the data such that there is another branch of your database that contains only the "Notes" property, and query that branch alone. This duplication is common in NoSQL type databases, and is call the "fan out" technique.
If you want to save download band then i can't help you further, otherelse:
let ArrayOfAllDownloadedNotes = [];
firebase.database().ref('yourRootFolders/vitals/Allergy').once((snapshot)=>{
ArrayOfAllDownloadedNotes = [...ArrayOfAllDownloadedNotes, snapshot.val().Notes];
});
//Reapeat the firebase formula for every child you want retrieve the Notes from
//You may also use forEach((item)=>{}) function for each folder you want to retrieve the //notes from if you want
console.log(My Array of Notes:',ArrayOfAllDownloadedNotes );