Perform key Specific Query in Firebase - java

I have structure for database in this manner
-... location
-... messages
-... id1_id2
-... id3_id4
-... id5_id6
.
.
.
How can I access a object in messages where I just know id1 which is the key.
TIA.

Change your database to this:
Messages
userid1
userid2
message: hello
then to retrieve message, do this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Messages").child(userid1);
ref.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot){
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String messages=ds.child("message").getValue().toString();
}
}
});

Try this one
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("location/messages");
ref.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot){
for (DataSnapshot ds : dataSnapshot.getChildren()) {
if(ds.getKey().contains("bob")){
//Do something with the date
break;
}
}
}
});

Suppose your structure is like this:
You can do something like this, this will grab all nodes from messages that start with id1:
String id1 = "id1";
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("messages");
ref.orderByKey().startAt(id1).endAt(id1 + "\uf8ff").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snap : dataSnapshot.getChildren()) {
Log.d("SNAP", snap.getValue(String.class));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I took the idea from the javascript implementation, but it also worked in Android, I've run a test on my device/database. Note that this method will work to grab data that starts with the given id.
EDIT:
The idea of querying firebase data that contains a certain string is discussed in this official post. Also, this question as well. The bottom line is that the api doesn't support these types of queries, the approach I mentioned above is the closest you can get of implementing a "SQL LIKE" in firebase. Currently, there's no way of searching for strings that END with another string. The endAt doesn't mean the string ends with id1, but rather that the range of values I want to retrieve finishes at (id1 + "\uf8ff"), that means any string starting with id1.
Your options are either change the schema or grab all messages and search locally (the suggestions of the other two answers).

Related

How to get the random key paired with a specific value in firebase database and delete the value?

I have a simple database structure like so:
I need to remove the value earphone by using its key which is -M-4XBDqv-ve396r5EHm.
I have a button for deleting that value,
and I want to use this line of code to remove it:
mReferenceForListA.child("List A").child("Items").child(key).removeValue().
But how do I get the key for earphone?
I know I can just write
mReferenceForListA.child("List A").child("Items").child(-M-4XBDqv-ve396r5EHm).removeValue()
to delete earphone straight away,
but what if I need to delete other items in the list?
I'll need to pass a specific key into a variable called "key" to delete a specific value.
So, again, how could I get a specific key for the value that I want to delete in my current JSON structure?
This is what I tried:
Reading through related posts for days in stackoverflow and I came down to writing the following codes, but I don't think I got the hang of this thing yet and seriously need help. The following codes always delete the whole "List A" node, but in this case I just need to delete one specified value and keep the others intact in the node.
public static DatabaseReference mRootReference = FirebaseDatabase.getInstance().getReference();
public static DatabaseReference mReferenceForListA = mRootReference.child("List A");
deleteButton= findViewById(R.id.delete_button)
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mReferenceForListA.child("Items").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postsnapshot :dataSnapshot.getChildren()) {
String key = postsnapshot.getKey();
mReferenceForListA.child("Items").child(key).removeValue();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
To delete a node you need to know its complete path. If you only know a value of (a property of) the node, you can run a query to find all nodes that match that value.
Something like:
public static DatabaseReference mRootReference = FirebaseDatabase.getInstance().getReference();
public static DatabaseReference mReferenceForListA = mRootReference.child("List A");
Query query = mReferenceForListA.child("Items").orderByValue().equalTo("earphone");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
snapshot.getRef().removeValue();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
The main changes:
The above uses a query on orderByValue() on the Items child. This means Firebase searches all child nodes directly under List A/Items and returns the ones whose value matches earphones.
It also uses addListenerForSingleValueEvent, so that the delete only runs once, instead of continuously.
It uses snapshot.getRef().removeValue() for a much shorter way to remove the node.
It implements onCancelled, since you should never ignore errors.
You should iterate through the DataSnapshot as you have done, but you also need to supply it with a condition to delete the entry with a specific value.
for (DataSnapshot postsnapshot : dataSnapshot.getChildren()) {
if(postsnapshot.child(postsnapshot.getKey()).getValue(String.class)).equals("earphone"){
mReferenceForListA.child("List A").child("Items").child(postsnapshot.getkey()).removeValue();
}
}
Let me know if this works as I am trying to write this from memory.

How to get a child's data when it has been pushed?

I am using the "push()" function to store objects into my firebase database and since it stores data with unique keys I can't change the stored objects values using what's mentionned in the documentation:
myRef.child("child name").setValue(model);
because I simply don't know the key. I wan wondering is there an other way to modify the data of firebase database.
I want to add a new child called "conversations" to the users and programmatically add childs to him .
and this is the databse structure:
If you have the following database:
Users
pushId
name : john
age : 100
In case you dont know the pushId, you can do the following:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
String key = ds.getKey();
String name = ds.child("name").getValue().toString();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
The above will get you the name and the key using getKey()

Firebase - query on nested key?

I'm running an Android app that handles some data on Events and Users who have been invited to them. I have a page that needs to show all the events that a user has been invited to, but I'm relatively new to Firebase and I'm not sure how the query syntax would work for my current data structure.
An example of my data-structure (with dummy keys) can be seen below:
events
event1_key
eventName: "test event"
eventAdmin: "userAdmin"
eventInvites
user1_key
attending: true
responseTimestamp: 1525416294951
user2_key
//...
event2_key
//...
eventInvites
user2_key
//...
user3_key
//...
So using this example, if I was looking for all the events that user1_key had been invited to, the query should only return the event1_key record, because that one has a nested eventInvite for user1_key.
If I'm running that query in Java for Android Studio, does anybody know what it should look like?
I think you need to replicate your data in another node in this case. Right now, you have a single node which keeps all the events (i.e. events node). I would suggest your create a separate table (i.e. separate node) for users as well.
That node structure might look like the following.
users
user1_key
events1_key
events2_key
...
user2_key
events5_key
events2_key
....
....
I this way you will not require any nested lookup. Just replicate the data here in this node as well when you are inserting the data under events node.
Hope that helps!
Update
If you are considering replicating your table, then the check for user is attending an event will be fairly simple like the following.
userRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
boolean attending = false;
for (DataSnapshot eventSnapshot : dataSnapshot.getChildren()) {
if(eventSnapshot.getKey().equals(THE_DESIRED_EVENT)) {
attending = true;
break;
}
}
if(attending) doSomethingAsUserIsFoundToBeAttendingTheEvent();
else userIsNotAttending();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
The code is not tested, I just have the pseudo implementation. Please modify as per your need.
To achieve what you want, I recommend add another node in your database structure that looks like this:
Firebase-root
|
--- userEvents
|
--- user1_key
|
--- event1_key: true
|
--- event2_key: true
In this way you'll be able to read all your events that correspond to a particular user at once without the need to download the enitire events object. To get those ids, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userKeyRef = rootRef.child("userEvents").child(userKey);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String eventKey = ds.getKey();
Log.d("TAG", eventKey);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
userKeyRef.addListenerForSingleValueEvent(valueEventListener);

Firebase: Getting specific field from a node based on field in another node

I have been googling from 3 hours now but have not been able to either phrase the search term correctly or there are no good solutions for it. I am using firebase for my android app. It has a structure like following:
The upper one is comments node
I have just displayed the comments using listview.
commentRef1= FirebaseDatabase.getInstance().getReference().child("Comments").child(postKey1);
commentRef1.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot ds: dataSnapshot.getChildren()){
comment1=ds.getValue(Comment.class);
arrayList.add(comment1);
}
commentList.setAdapter(adapter);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
But as with every relational database, I am trying to save just id or uid in comments(table) or node(rather than whole username).
But, now I am having PROBLEM querying or DISPLAYING USERNAME while displaying comments from the users node (i.e display name) as uid only is saved in comments node.
I found some of the methods like doing nested oneventlistener and so on but little bit confused with the complications and effort need for it.
It would have been simple query or nested select in any sql languages.
Can anybody help? How can i retrieve username or specific value in that query. I saw many storing the while username in comments table. I don't think it is right approach.
To get the full_name, you need to do the following:
DatabaseReference ref=FirebaseDatabase.getInstance().getReference();
commentRef1= FirebaseDatabase.getInstance().getReference().child("Comments").child(postKey1);
commentRef1.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot ds: dataSnapshot.getChildren()){
String userid=ds.child("uid").getValue().toString();
ref.child("Users").orderByKey().equalTo(userid).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String fullname=dataSnapshot.child("full_name").getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
You can use nested listener, I guess you want the user to type the comment then click on a button and creates a node for the comment with a uid,post_id,comment.
Then you want to retrieve the comment to display it with the information, so the datasnapshot will be on Comments/postKey1 then you can retrieve the information there(including the uid), then use orderByKey().equalTo(userid) to be able to retrieve the fullname of the user from the node Users
To avoid all of this just add the fullname in the Comments node instead of the userid
https://firebase.googleblog.com/2013/04/denormalizing-your-data-is-normal.html

Firebase Android get value by child key

I have the following database structure in Firebase:
I would like to retrieve all objects from "chats" if in the "users" object contains the key "user2".
Is it possible to download the data as written with no change of structure Firebase?
My actually code to get data:
DatabaseReference chatReference = FirebaseDatabase.getInstance().getReference("conversationsNew");
chatReference.orderByChild("users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("TAG", dataSnapshot.getChildrenCount());
for (DataSnapshot chat : dataSnapshot.getChildren()) {
Log.d("TAG", chat.toString());
Chat chat = chat.getValue(Chat.class);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Thank you very much.
That's quite possible:
DatabaseReference chatReference = FirebaseDatabase.getInstance().getReference("chats");
chatReference.orderByChild("users/user1").equalTo(true).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot chat: dataSnapshot.getChildren()) {
Log.d("TAG", chat.getKey());
Chat chat = chat.getValue(Chat.class);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
This will print:
chat1
But this approach will not scale, since you'll need to add an index for each user. To prevent this, you'll need a data structure that more closely reflects the use-case. So: if you want to show a list of the chats that the current user is in, you'll need to store precisely that: a list of the chats for each user. Alex' answer shows the most common way of storing such data.
No, there is no possibility for achieving this using your code. What can you do instead, is to change a little bit your database structure, by adding a new node like this:
Firebase-root
--- users
--- userId1
--- userName: John
--- chats
--- chat1: true
Having this, you can query your database for getting the chats in which your user belong. To verify for existens you only need to use exists() method on the dataSnapshot object.
Hope it helps.

Categories