Firebase Database: get all child's data from childs - android

I want to be able to differentiate my content between type and get all other data but I don't know how to get past the IDs after content.
I want every data from -NBC22CHEk3ebNxdlYOi, -NBC-Nfz6e5yppFlxU7S, -NBC1TVY-TzT7yfrSA3o
and later be possible to get new video id's from existing and new users
/content/{user_uid}/{content_uid}
If I want only the content from one user then I can write this:
val uid = FirebaseAuth.getInstance().uid
// url is just a placeholder for the real database url
val ref = FirebaseDatabase.getInstance(url).getReference("/content/$uid")

I want all content with the type value "video" from all users.
That's actually not possible with your actual database structure. All queries in the Realtime Database work on a flat list of nodes, where the value on which you want to perform the filter/order on, must be at a fixed path under each direct child node.
Unfortunately, that's not your case, because you have a dynamic key under the content node, which is actually the UID, and which also means that you can't filter on type. If you want to allow that, then you have to create a flat list of videos, where the UID (SIH5...89j1) is a property inside each video object. This is already achieved since publisher_uid holds exactly that.
In short, remove the extra (UID) level from your database tree. Or, leave it as it is, and denormalize the data. Basically create a new structure like this:
/content/{content_uid}
See, there is no UID involved. If you're new to NoSQL databases, this might sound some kind of weird, but it's actually a quite common practice.

Related

Android Livedata Room. Which method to use

In my Android Kotlin App. User profile (A form) needs to be updated using data from RestAPI eg. education and location data from API looks like this
{"educations": [{"edu_uid": 123, "edu_sector": "xxxx", "edu_degree": "xxx"}, .....}
{"locations": [{"loc_uid": 123, "loc_place": "xxxx", "loc_zip": "xxx"}, .....}
After consuming this data. We show it in an adapter. User choose his choice. We update XML views like #id/textViewEduSector and #id/textViewEduDegree. After filling up the form, When the User submit data I send only "edu_uid" "loc_uid" to the Server. Here is representation of my implementation:
profile_fragment -> education_fragment -> education_adapter onEducationClick ->
navigateUp() -> profile_fragment update #id/textViewEduSector and #id/textViewEduDegree.
Then location and so. At the end when User submit the form,how can I pick "edu_uid" and "loc_uid" to sendback data to API endponit eg. "/profile/update".
How can I collect these uids temporarily. I have a Room database with all User fields. Here I donot want to retain hidden fields, "edu_uid" or "loc_uid". Is it necessary to update Room via Dao and then picking data from there and sent to API or any other workaround.? Fast and efficient?
Since it is hard to get the point of your problem, i try to give my general thoughts about your use-case.
Try to separate next issues:
What is single source of truth in your app? Is it a local database? If not - why?
How to represent you data sources in UI?
How to synchronise your data structures with server?
Data structures. Try to use a database (ROOM) as a single source of truth in your app. If you do, you get additional benefits of working without access to Rest API. In this case your ROOM-entities set should include - Education (edu_uid as Primary Key), Location (loc_uid as Primary Key) and User/UserProfile (with edu_uid and loc_uid as Foreign keys). In this case you should't add fields "edu_sector" or "edu_degree" to UserProfile data class. And with a action "submit" you have to save changes to your local database (with edu_id and loc_uid) and to solve your "REST API-question" at next step.
Representation in UI. If you use MVVM, you should't have a problems with "edu_id" or "loc_id". You declare references to Education and Location in your ViewModel and in your XML you can easy consume any fields of these objects.
Sync with server. It should be easy if you have efficient local database with all needed fields as foreign keys (again in your DAO you can get all the rest fields you want from other tables with table joins)
Again, maybe I didn't get your real problem. It is really unclear

Firebase Realtime database Array query issue [duplicate]

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.

Is better to use random ID for firebase document or manual ID?

In your opinion, is better to use the random ID auto generated by firebase for a new document or it's not a bad practice if I choose the name of the document so that I can perform easier query?
For example, instead of searching inside the collection "users" in all the random id document, and then search for a user with the field "email = test#gmail.com", should I assign to my document the title "test#gmail.com" and then search on the collection "users" for the document with the name "test#gmail.com"?
What do you think?
This is difficult to answer because you're asking for an opinion about your database structure when we have no concept of your use case.
However, let me throw out a couple of thoughts.
if I choose the name of the document so that I can perform easier
query
The key name is not related nor has anything to do with the child data it contains as far as a query goes. take a look
users
-Y89j9kksd0kskd //a users uid for example
email: "thing#test.com"
-y9099k,msp,sps
email: "dude#thing.com"
If you want to query for an email of "dude#thing.com", the query 'ignores' each child key (-Y89... -y90... etc) and looks at the email: node within.
If you name the keys and do a query, it still makes no difference, it still ignores that key. It is returned as the key property of the snapshot but that's not the issue here since we know the value is the email of the email: child.
users
-thing#test.com
email: "thing#test.com"
-dude#thing.com
email: "dude#thing.com"
The issue here is that . cannot be used in key names so now you have to encode/decode every key. That's a lot of extra code.
More importantly, if the email address changes, you will have to change every occurrence of that email address in ALL of your data. And since you can't change keys, you would have to delete every node and re-write it. Ugh.
Using the first example is the way to go. You can keep a reference to that user throughout the app (using the uid for example) and no matter what child data changes within that node (email for example), the rest of the data remains unaffected.
There is a but here... there's always a but.
Sometimes you may want to know if a piece of data exists at specific path - in those cases, you can access it directly. For example
users
-Y89j9kksd0kskd //a users uid for example
email: "thing#test.com"
things_i_like
food:
pizza: true
taco: true
color:
blue: true
wine:
ornellaia: true
Suppose I have this users uid of -Y89j9kksd0kskd and I want to see if pizza is a food they like. Instead of querying the food node I can access it directly at
/uid/things_i_like/food/pizza
and see if the value is true (or see if it exists)
or to see if they like the wonderful Italian Ornellaia wine, test for true (or existance) at
/uid/things_i_like/wine/ornellaia
As you can see, leveraging the uid or Firebase created keys at a top level doesn't affect your queries but when you know you want to access a specific datapoint within a known node, naming the node keys is one solution.
It's all a balance and depends on what kind of queries you want to run... If you wanted to know all users that like pizza, that would be a query (and a slightly different structure) so you wouldn't know the specific path and a query would be needed.

Can Firebase return only some of the attributes? [duplicate]

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 );

How to save data on top of the already saved data in Firebase?

I am saving some data in FirebaseDatabase under a child as a key:value pair.
The problem is that data is getting saved as pushed, like if data1 is saved already than data2 will get saved below it. I want to save it above this already saved data.
Here is the data structure:
- branch
- child
- uniqueKey1: data1
- uniqueKey2: data2
I am saving the data using this code:
String key = mDatabase.child("branch").child("child").push().getKey();
mDatabase.child("branch").child("child").child(key).setValue(data);
What I want is the structure below:
- branch
- child
- uniqueKey2: data2
- uniqueKey1: data1
How to save the newly added data above the already saved data? Please let me know.
In your firebase database, childs in a node are ordered in alphabetical order, no matter which order you save them.
If you want to retrieve them later in some specific order, let's say order by date added, you might want to create a timestamp reference.
Check here:
How to sort value inside a Firebase child to the rest?
Edit: a lot of answers and edited questions while writing my answer, but as others mentioned you should not worry about the order you see the data in the database, you should only care to provide the right structure to retrieve the data correctly.
As I said, in the DB the childs are ordered in alphabetical order so if you insist on ordering it by date added you should figure out a way to update the key accordingly and then update the whole node.
I don't think the order in which you save data is important as long as you have a strategy to retrieve it correctly in your order of choice. Firebase provides API to retrieve data ordered by either key or value.
Work with Lists of Data on Android
If you just want to retrieve the record first which was added last, you can put a timestamp that accompanies your data. There are also methods that gets you last record of a collection.
What you are trying to do is update data1. Then what you have to do is,
Get reference of the node you want to update.
DatabaseReference ref = mDatabase.child("branch").child("child").child("data1");
then update the child node. I'm assuming there is a child name under data1, whose value is 'Foo'. And now you want to update it 'Bar'.
Hashmap<String, String> map = new Hashmap();
map.put("name","Bar");
ref.updateChildren(map);
This is how you update a node. If you want to completely replace the node, then you can delete the node and by calling removeValue() method and pushing the data again!.

Categories

Resources