I'm using Firebase in my Android Project. I have a ValueEventListener and it keeps on getting the old value even the node is already modified by other devices. It seems like it is disregarding the updates made by other devices.
Here's my code:
ValueEventListener listener = destinationDatabaseReference.child(somestring)
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue()==null)
{
}
else
{
//here I keep on getting the old value
string value = (long) dataSnapshot.child("someString").getValue();
}
}
use the query like this:-
Query query = mDatabase.getReference().child("posts").orderByChild("date").limitToLast(1);
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot!=null){
String notific = String.valueOf(dataSnapshot.getValue());
Log.d("key",dataSnapshot.getKey());
Log.d("title",String.valueOf(dataSnapshot.child("title").getValue()));
Log.d("content",String.valueOf(dataSnapshot.child("content").getValue()));
}
}
Thanks guys for all the help. I tried your suggestions but it did not work for me :(
However, I found this link and I would like to share just in case someone needs it.
For this kind of issue, you have to use Transaction Operations. Please see related useful links below:
Updating firebase data in several devices by Transaction Operations
Similar Question with Working Answer
Try to use a final reference like this:
URL url = new URL(yourURL);
final Firebase root = new Firebase(url.toString());
root.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue()==null)
{
}
else
{
//here I keep on getting the old value
string value = (long) dataSnapshot.child("someString").getValue();
}
}
Related
I am trying to retrieve a nested list of workouts from a Realtime Database and I don't know how to do it.
I made some research and still couldn't really figure out how am supposed to do it.
The Realtime Database JSON file looks like this :
I am looking to retrieve data by workout, for example, if someone presses the workout one button I should retrieve the full workout one object. but I don't know how am supposed to design my query request nor how am supposed to structure my model object that conceives the received data.
As I see in your screenshot, under the "Workout one" node, you have two nested levels of data. So to get all exercises for each day, you have to loop over the children twice:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference workoutOneRef = db.child("Fat Loss").child("Workout one");
workoutOneRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
for (DataSnapshot daySnapshot : task.getResult().getChildren()) {
for (DataSnapshot exerciseSnapshot : daySnapshot.getChildren()) {
String name = exerciseSnapshot.child("name").getValue(String.class);
Log.d("TAG", name);
}
}
} else {
Log.d("TAG", task.getException().getMessage()); //Never ignore potential errors!
}
}
});
Please also don't forget that the Firebase API is asynchronous. So any code that needs data from the database needs to be inside the onComplete() method, or be called from there. To understand better, I recommend you check the following resource:
How to read data from Firebase Realtime Database using get()?
I think below line code help you.
databaseReference = FirebaseDatabase.getInstance().getReference().child("Fat Loss").child("Workout one").child("day 1")
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
allTaskList.clear();
if (snapshot.exists()) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
//modal class object
AddTODOListModal model = dataSnapshot.getValue(AddTODOListModal.class);
assert model != null;
model.setId(dataSnapshot.getKey());
allTaskList.add(model);
}
adapter = new TODOListAdapter(TODOListHomeActivity.this, allTaskList);
binding.rvTODO.setAdapter(adapter);
}else {
Utils.showToast("No Data Available");
}
Utils.dismissProgressDialog();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Utils.showToast(error.getDetails());
}
});
Reference link :- https://firebase.google.com/docs/database/android/lists-of-data
I have three objects (Book, Listicle_modell and Feed_modell) and I want to retrieve in a list of objects.
But I'm obtaining data from Firebase Database that does not exist.
My firebase structure:
-userid
- key
-name2: Nova Conta
-title: The best music in the world;
-thumbnail: url;
enter image description here**i just have one child, why I'm getting Firebase give me three objects ? **.
In my Database I just have one child that has values that matchs Feed_modell, but I'm getting the layout from book and listicles either without having these objects (keys that match book.class and listicle) in my database as the pics show:
The problem is this: ** these two images that have no title, no thumbnail, no name, just have a views written, are being called but they do not exist, the Test Ad is working perfectly.
This is my Android code:
dbforFeed = FirebaseDatabase.getInstance().getReference("feedPosts").child(feedReceivingKey);
dbforFeed.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Feed_modell post = dataSnapshot.getValue(Feed_modell.class);
Book book = dataSnapshot.getValue(Book.class);
Listicle_modell lm = dataSnapshot.getValue(Listicle_modell.class);
feedList.addAll(Arrays.asList(post, book, new all_modell("ca-app-pub-4452407171570296~9731286762"), lm));
recyclerViewFeedAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged( DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved( DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved( DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled( DatabaseError databaseError) {
}
});
Here is my database structure
An important practice when using a NoSQL database is to have under a node (feedPosts), objects of the same type. As I understand from your comment:
Feed_modell has. Just Feed_modell has these fields.
The existing object is of type Feed_modell. As I see in your code, from the same dataSnapshot object you are trying to get three different objects Feed_modell, Book and Listicle_modell, which is not correct. A single dataSnapshot can be converted to a single object type. To solve this, please see the following changes:
List<Listicle_modell> feedList = new ArrayList<>();
//Feed_modell post = dataSnapshot.getValue(Feed_modell.class);
//Book book = dataSnapshot.getValue(Book.class);
Listicle_modell lm = dataSnapshot.getValue(Listicle_modell.class);
feedList.add(lm);
recyclerViewFeedAdapter.notifyDataSetChanged();
Make sure your adapter is also of type Listicle_modell.
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).
I want to display only children of location i.e Sindh and Punjab (not their children). Is it possible, and if so how can I do it?
From Best practices for data structure in the docs:
Avoid nesting data
Because the Firebase Realtime Database allows nesting data up to 32
levels deep, you might be tempted to think that this should be the
default structure. However, when you fetch data at a location in your
database, you also retrieve all of its child nodes. In addition, when
you grant someone read or write access at a node in your database, you
also grant them access to all data under that node. Therefore, in
practice, it's best to keep your data structure as flat as possible.
That is how Firebase works: If you get an item, you get its children as well. If you don't want this, you should restructure the database.
Avoid Nesting Data
Because the Firebase Realtime Database allows nesting data up to 32 levels deep, you might be tempted to think that this should be the default structure. However, when you fetch data at a location in your database, you also retrieve all of its child nodes. In addition, when you grant someone read or write access at a node in your database, you also grant them access to all data under that node. Therefore, in practice, it's best to keep your data structure as flat as possible.
Below is a structure of yours on how to implement flat database as well as how to retrieve the location key.
{
"location": {
"punjab": {
"lahore": true,
"multan": true
},
"sindh": {
"karachi": true
}
},
"place": {
"lahore": {
"location": "punjab",
"details": {
"0": "model",
"1": "steel town"
}
},
"multan": {
"location": "punjab",
"contacts": {
"0": "myarea"
}
},
"karachi": {
"location": "sindh",
"contacts": {
"0": "hadeed",
"1": "Steel town"
}
}
}
}
Below is the code that you can use to retrieve the location key.
private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
mLocation = mDatabase.child("location");
mPlace = mDatabase.child("place");
ValueEventListener placeListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Place place = dataSnapshot.getValue(Place.class);
String location = place.location;
System.out.println(location);
}
};
mPlace.addValueEventListener(placeListener);
For more information on Firebase:
Firebase Security & Rules
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("location");
final ArrayList<String> statesArrayList= new ArrayList<>();
databaseReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
statesArrayList.add(dataSnapshot.getKey());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Yes, you can
ValueEventListener getValueListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get data from firebase
Log.d("The name of child that you need:", dataSnapshot.getKey());
// ...
}
};
databaseReference.addValueEventListener(getValueListener );
Read more: https://firebase.google.com/docs/database/android/read-and-write#listen_for_value_events
Though nesting data is not recommended in NoSQL databases like Firebase, to get the name of child nodes your code will look like this
DatabaseReference mainRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference locationref = mainRef.child("location");
final ArrayList<String> locationNames = new ArrayList<>();
locationref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
locationNames.add(dataSnapshot.getKey());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
You can now use locationNames to do what you want.
Firebase can as quickly look up a node at level 1 as it can at level 32. Depth is not a factor that affects speed on a technical level but years of experience with Firebase has shown that deeply nested data often goes hand in hand with performance problems. As an example, i recomand you reading the offical documentation, Best practices for data structure in Firebase and Structuring your Firebase Data correctly for a Complex App.
If you don't want to change your actual database structure and assuming that location node is a direct child of your Firebase root, please see the code below:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference locationRef = rootRef.child("location");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String key = ds.getKey();
Log.d("TAG", key);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
locationRef.addListenerForSingleValueEvent(eventListener);
Your output will be:
punjab
sindh
I know this question was asked a while ago and for android, but I was looking for a solution to this and came upon this question. I couldn't use the answers provided, so here is the solution I found. This will only get the children and nothing else.
This is in javascript, but you can use whichever method is the alternative in java to make a request from a REST endpoint.
const databaseURL = "https://example.firebaseio.com" // replace value with yours
const endpoint = "location"
const user = firebase.auth().currentUser
user.getIdToken()
.then(token => {
return fetch(`${databaseURL}/${endpoint}.json?auth=${token}&shallow=true`)
})
.then(response => {
return response.json()
})
.then(json => {
console.log({json}) // contains only the children
})
.catch(error => {
console.log(error.message)
})
The important bit here is the &shallow=true otherwise you get all the data in the children.
Using curl this would be
curl 'https://example.firebaseio.com/location.json?auth=INSERT_TOKEN&shallow=true'
This assumes location is a child of the root.
More details can be had by looking at the docs
Before calling this, you have to make sure you have the currentUser available in firebase.
Also, I would heed the warnings mentioned here about proper firebase realtime database structure. However, if you are already in this spot, then this can help.
This is how u can get child names
HashMap<String, Object> allData = (HashMap<String, Object>) dataSnapshot.getValue();
String[] yourChildArray = allData.keySet().toArray(new String[0]);
System.out.println(ref.child("mostafa_farahat22#yahoo.com").child("_email"));
*i`m trying to get a value of child but all time i get the URL of the value
how to get the value of this URL as i try by this code but it get me the URLi want to get the _email value.
You are looking at the concept from the wrong angle.
While using the ref.child("mostafa_farahat22#yahoo.com").child("_email") you are just simply pointing at a particular place in your database and nothing more.
If you want to retrieve the data in that particular place, consider these 2 ways.
First if you want to retrieve the data only once, you can do the following :
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
DatabaseReference mostafa = ref.child("Users").child("mostafa_farahat22#yahoo.com").child("_email");
mostafa.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String email = dataSnapshot.getValue(String.class);
//do what you want with the email
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
or maybe you want to retrieve the value in real time and use it in the same time that the database value is changed, all in the same time, whenever the value in changed, then you use this :
mostafa.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String email = dataSnapshot.getValue(String.class);
display.setText(email);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Note the difference between the two methods. First is only for one time retrieve and the second is for retrieving the data whenever the value is changed.
Just have in mind that the codes that i posted are just templates and may need to play with them a bit.
With ref.child("mostafa_farahat22#yahoo.com").child("_email") you are just setting the reference to the object. Take a look at the java firebase documentation to retrieve data.
To get the data you will need to set a listener for your reference
ref.child("mostafa_farahat22#yahoo.com").child("_email").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
// data available in snapshot.value()
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});