I am making a SearchView in the search bar to filter all processes that started or ended within a certain date.
I need to get a query of nodes inside processes and codes.
Here is my data structure and what I need to query:
I'm using this for the codes as an example:
//path of all posts
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("codes");
//get all data from this ref
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds: snapshot.getChildren()) {
String hola = Objects.requireNonNull(ds.getValue()).toString();
if (ds.hasChild("process")) {
for (DataSnapshot dsa: ds.getChildren()) {
System.out.println("result"+dsa);
/* if (!isEmpty(Objects.requireNonNull(dsa.child("ended").getValue()).toString())) {
System.out.println("result: "+dsa.child("ended").getValue().toString());
}
*/
}
But I need to obtain the node of other children, preferably without changing the data structure:
I have a FirebaseRecyclerOption where everything is loaded, and I need to only show the holders filtered from the SearchView.
If you're allowed to change the database schema, a more convenient way of storing the data would be to have a flattened structure like this:
Firebase-root
|
--- codes
|
--- $pushedId
|
--- code: 17240
|
--- proces: "Cajones"
|
--- user: "Jose Anton"
|
--- started: longNumberForStarted
|
--- ended: longNumberForEnded
Things I recommend:
Don't use sequential numbers as keys in the database. Use the unique random IDs that are generated by the push() method.
Don't store dates as strings, rather store them as timestamps.
In this way, you'll be able to filter the results as needed. And since you're using timestamps you'll be able to use startAt() or endAt() if you need.
Due to the formatting of the date in the string, it will not be possible to filter or sort the data on the server side. If it was formatted "yyyy.MM.dd a les HH:mm:ss" it would still be possible because they would be in order of magnitude, but arranged this way I can only imagine you reading all the nodes and reordering in a local list ( I don't think it's a good idea).
My suggestion is that you replace the format of this time field to something like a TIMESTAMP from the firebase itself with the server time or if they are custom times, convert them and re-store them.
If you do, you can create custom filters and order them on the server itself, as needed, using orderByChild(), orderByKey(), orderByValue(), limitToFirst(), limitToLast(), startAt(), startAfter(), endAt (), endBefore() and equalTo().
Related
I am using FirebaseRecyclerOptions in calling the database, however, I cannot get all of the data in the database. Here is the structure of the database: database structure the yellow underline is the user id (UID) and below is another node that contains the data that I want to retrieve in the RecyclerView.
Here is a snippet of the code
FirebaseRecyclerOptions<RegisterParking> options =
new FirebaseRecyclerOptions.Builder<RegisterParking>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("RegParkingArea"), RegisterParking.class)
.build();
voPListAdapter = new VoPListAdapter(options);
recyclerView.setAdapter(voPListAdapter);
When you're passing the following two arguments to the setQuery() method:
.setQuery(FirebaseDatabase.getInstance().getReference().child("RegParkingArea"), RegisterParking.class)
It means that the adapter expects to render on the screen RegisterParking objects. If you take a closer look at your database schema, under the RegParkingArea node, you can find UIDs and not RegisterParking objects. The objects that you want to display in the RecycerView exist under each UID. So when reading the data from the database, the Firebase-UI library tries to map each child under the above reference into an object of type RegisterParking, which is actually not possible since the UIDs are strings.
So if you're allowed to change the database schema, then you should either denormalize the data, basically copying the data under another node, or change the actual data into:
db-root
|
--- RegParkingArea
|
--- $pushedId
|
--- uid: "4u9h...XrP2"
|
--- //other fields.
What I have basically done, I have removed a level from the database tree. If you'll use this schema, then you can leave the code as it is and everything will work perfectly fine.
One more thing to note is that if you need to get all parking of a particular user, then you can use the following query:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
Query queryByUid = db.child("RegParkingArea").orderByChild("uid").equalTo(uid);
new database structure
This is how I show data for each user using FirebaseRecyclerOptions.
But I want to get all children data for only a specific user with a condition by checking users with UID or any other solution.
Ps : This post was edited many times because of the database structure has been changed
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_pdv, container, false);
recyclerView = v.findViewById(R.id.pdv_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
if (user_id.equals("hZBCb9yk8ycamjoVcISjG2y4ZnI2")){
Query query = FirebaseDatabase.getInstance("https://dtechapp-94795-default-rtdb.europe-west1.firebasedatabase.app")
.getReference().child("commande").orderByChild("user_id").equalTo("hZBCb9yk8ycamjoVcISjG2y4ZnI2"); ;
FirebaseRecyclerOptions<Order> options =
new FirebaseRecyclerOptions.Builder<Order>()
.setQuery(query, Order.class)
.build();
pdvAdapter = new PdvAdapter(options);
recyclerView.setAdapter(pdvAdapter);
return v;
}
}
When you using the following query:
Query query = FirebaseDatabase.getInstance("https://dtechapp-94795-default-rtdb.europe-west1.firebasedatabase.app")
.getReference("pdv").child("user_id");
It means that you are trying to read data from:
rootRef/pdv/user_id
Such a reference actually doesn't exist. Under your "pdv" node there is no child called "user_id", but one called "fP0LLs83MYZqX9BqYO24IX80F3Q2". So you either use:
Query query = FirebaseDatabase.getInstance("https://dtechapp-94795-default-rtdb.europe-west1.firebasedatabase.app")
.getReference("pdv").child("fP0LLs83MYZqX9BqYO24IX80F3Q2");
Or if that UID of the user that comes from a Firebase authentication operation, you can then simply use:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
Query query = FirebaseDatabase.getInstance("https://dtechapp-94795-default-rtdb.europe-west1.firebasedatabase.app")
.getReference("pdv").child(uid);
Edit:
According to one of your comments:
So I want to get data from children of all users at the same time. This is 1st user "fP0LLs83MYZqX9BqYO24IX80F3Q2" I want to get children inside him and at the same time, I want to get children from 2nd user "hZBCb9yk8ycamjoVcISjG2y4ZnI2" and display it in my RecyclerView.
And according to your database schema, please note that you cannot achieve that. There is no way you can get all users having such a schema. Queries in the Realtime Database work on a flat list of nodes. Besides that, you have an unknown key under the UID node, which makes it impossible to query. To solve this, you should consider removing one level in your tree, and add "Amine" and "Zouaoui..." as properties inside each UID node. Your schema should look like this:
Firebase-root
|
--- pvd
|
--- $uid
| |
| --- type: "Amine..."
| |
| --- //Other fields.
|
--- $uid
|
--- type: "Zouaoui..."
|
--- //Other fields.
The code may remain unchanged.
I'm a little stuck, to create FirebaseRecyclerOptions that should present the results in recursive in database
I mean if I had in Data base (Crossfit - > APR_09_2021 -> 10_12 -> "some data collection")
So I noticed if I didn't pass the specific path to "some data collection" so it can't retrieve the data
I mean: DatabaseReference mbase = FirebaseDatabase.getInstance().getReference().child("Crossfit").child(APR_09_2021)
So my question how do I get all results from the database.
for all the dates that I have under the CrossFit
Thanks.
DatabaseReference mbase = FirebaseDatabase.getInstance().getReference().child("Crossfit");
recyclerView = findViewById(R.id.recycler_plan);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
FirebaseRecyclerOptions<TrainingTrainerCollector> options = new FirebaseRecyclerOptions.Builder<TrainingTrainerCollector>()
.setQuery(mbase, TrainingTrainerCollector.class).build();
recycleViewAdapter = new TrainerRecyclerviewViewAdapter(options,"Crossfit");
recyclerView.setAdapter(recycleViewAdapter);
recycleViewAdapter.startListening();
super.onStart();
https://i.stack.imgur.com/x4Fik.png
https://i.stack.imgur.com/1CW2U.png
You cannot do that with your actual database structure. When you are using the following reference:
DatabaseReference mbase = FirebaseDatabase.getInstance().getReference().child("Crossfit");
It means that you are trying to read all children under "Crossfit". So when using the Firebase-UI library, it means that you can only get children one level deep. According to your schema, your data is two-level deep, see?
APR_10_2021 -> 10_12 -> Data
There are two ways in which you can solve this. The first option you have is to create a new node called "allCrossfits" where you should add all "TrainingTrainerCollector" objects. This practice is called denormalization and is a common practice when it comes to Firebase. If you are new to NoSQL databases, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding.
So, your new reference should look like this:
DatabaseReference mbase = FirebaseDatabase.getInstance().getReference().child("allCrossfits");
This reference should be passed to the "options" object.
The second option that you have is to remove the "time" level from your database tree, as it is already present in your "time" field. So new your schema should look like this:
Firebase-root
|
--- Crossfit
|
--- APR_10_2021
| |
| --- Current_Participant: "0"
| |
| --- Date: "APR 10 2021"
| |
| --- Max_Participant: "5"
| |
| --- Time: "10:00-12:00"
|
--- APR_14_2021
|
--- //Data
In this case, you only need to change the way you are adding the data to the database. Your actual "mbase" reference will perfectly fine.
i have been trying to retrieve the Data "in red" without knowing "the blue" key's value ( assuming there is multiple child with random keys) ,but i couldn't come up with the appropriate code .
This is the Firebase Children tree.
I tried to write this code but it doesn't work (i am a beginner)
List<String> idlist = new ArrayList<String>();
DatabaseStage = FirebaseDatabase.getInstance().getReference("Stages");
Query query = DatabaseStage.orderByChild("uniqueId").equalTo(stageid);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Iterable<DataSnapshot> stagedata = dataSnapshot.child("userEtudList").getChildren();
for(DataSnapshot it: stagedata){
if (!(it.getValue().equals("test"))){
idlist.add(it.getValue().toString());
}
}
Ps : if you are wondering about the use of orderByChild(uniqueId).equalTo(stageid) in this case stageid is equal to 2fdedf71-4346-4395-bee5-38db04d4fd47 it allows me to select one specific child which is the second one .
Here is the state of the variables obtained using breakpoints as you can see the Datasnapshot it keeps getting {key = userEtudList , Value =null} but not getting to Children
For the purposes of this answer I'm interpreting your question as "I want to generate a list of all values, without regard for their key, in the userEtudList node of the selected Stages node. (e.g. tell me which students are in that course). Likewise, that your code that deals with the test values is really just test code and isn't really relevant to this challenge.
Your problem is that dataSnapshot isn't really a single node. Its a set of all matching nodes at the level of the database where you made the query. The fact that there is only one item in this case because of your equalTo doesn't really matter. (e.g. imagine how this code works without your equalTo call in the query -- it can't, since it doesn't know which item in the snapshot to get the userEtudList child from!). This is why when you try to get the userEtudList child the snapshot is empty. Doc Reference
Calling getValue() on a snapshot returns the Java object representation of the data. If no data exists at the location, calling getValue() returns null.
To fix this, you should probably assert that dataSnapshot.getChildrenCount() == 1 and then:
Iterable<DataSnapshot> stagedata = dataSnapshot.getChildren()
.iterator().next()
.child("userEtudList").getChildren();
If you were able to somehow rely on the key name always being equal to uniqueId (its not clear to me why you are storing uniqueId as something other than the key anyway // possibly, this is just an artifact of using a screenshot of the database) you could avoid this by:
Iterable<DataSnapshot> stagedata = dataSnapshot.child(stageid)
.child("userEtudList").getChildren();
Of course, in this case, the entire query can be removed and you can just retrieve this node directly in the first place.
So i figured it out this is what worked for me
DatabaseStage = FirebaseDatabase.getInstance().getReference("Stages").child(stageid).child("userEtudList");
DatabaseStage.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mData.clear();
for(DataSnapshot data:dataSnapshot.getChildren()){
mData.add(data);
Firebase Database queries can have at most one unknown key. So unless you know either the 2fded...fd47 key of the 0 key, there's no way to look up the specific node you've marked in red.
I need to add data to an array stored in the database to be like this:
places:
0:"new Item"
1:"new Item",
2:"new Item"
.
.
.
My problem is How to push data in array stored in the Firebase without the need to use a Hashmap? For exemple the next data pushed will result on:
places:
0:"old Item"
1:"vItem",
2:"old Item",
3:"new Item"
I know that if i use the method given bellow, the data will be erased and a new data set will be added,
Utils.eventsRef.child(events.getUid()).child("arrayTicket").setValue(str);
Can someone help me please ?
According to your comments, to be able to add an array into your Firebase realtime database, you need first to convert your array to a List like in the following lines of code:
String[] items = {"newItem", "newItem", "newItem"};
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference arrayTicketRef = rootRef.child("arrayTicket");
arrayTicketRef.setValue(Arrays.asList(items));
The result in your Firebase console will be:
Firebase-root
|
--- arrayTicket
|
--- 0: "newItem"
|
--- 1: "newItem"
|
--- 2: "newItem"