I'm trying to display the "loc" of a part if its part number I given.
Here is what the data structure looks like:
{
"parts":{
"14521845": { "name":"TOOL EC160B/EC180B/EC210B/EC240", "loc":"EXC1", "sloc":"B3EGU01C03"},
"12829050": { "name":"SWITCH; IGNITION SWITCH", "loc":"PS01", "sloc":"85-06-013"},
"12829050": { "name":"SWITCH; IGNITION SWITCH", "loc":"COM1", "sloc":"B3RGK03D06"},
"20044893": { "name":"PARTS CATALOG_ENG_SPA_FRE_GER_KOR_EC210D", "loc":"EXC1", "sloc":"B3EGT01B02"}
}
}
Activity Code:
FirebaseDatabase firebaseDatabase=FirebaseDatabase.getInstance();
DatabaseReference databaseReference =firebaseDatabase.getReference("parts/"+curP);
databaseReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Products data=dataSnapshot.getValue(Products.class);
Log.i("",String.valueOf(data.getLoc()));
}
getLoc is the getter function for the Product class, and it returns the corresponding "loc" for the given curP. curP denoted the child values in parts.
The logic seems right to me, but I am not getting an output. Where am I going wrong here?
try this
getReference("parts").child(curP).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Products data = dataSnapshot.getValue(Products.class);
Log.i("", String.valueOf(data.getLoc()));
}
});
The problem is that what you are getting in onChildAdded() is not a whole Product object as you expect it to be.
In your database reference you are targeting a specific Product ("parts/"+curP) but using a ChildEventListener. The children of a specific product node are name, loc and sloc, so the onChildAdded() will trigger several times, giving you each of these properties as a dataSnapshot separately.
The two patterns you might use to get whole Product objects are either:
add a ChildEventListener directly to the "parts" node and you will get each of the Products as a child of that node, or;
if you are adding a listener directly to the node of a particular product, use a ValueEventListener, to get the whole of that nodes entry as one dataSnapshot.
You can try to use ValueEventListener. If you want read data once so use the addListenerForSingleValueEvent method, something like this:
private void getFirebaseLocValue(int curP) {
FirebaseDatabase firebase = FirebaseDatabase.getInstance();
DatabaseReference mDatabase = firebase.getReference("parts");
mDatabase.child(Integer.toString(curP))
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChildren()) {
Products data = dataSnapshot.getValue(Products.class);
Log.e("TAG", data.getLoc());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Or you can use addValueEventListener and will get data with any changes. I really don't think that ChildEventListener is a good idea to retrieve data from Firebase.
Related
addValueEventListener gives all the data whenever something changed in the database, due to this I have implemented addChildEventListener to get the only new item when there is a something new in the database.
Currently, the problem I am facing is whenever I open app, addChildEventListener fetch all the item one by one in onChildAdded method.
Is there any way that I can fetch only new items in Firebase Realtime Database? Here is my code:
mDatabase.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildAdded", news.getId()+"/"+news.getHeadline());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildChanged", news.getId()+"/"+news.getHeadline());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildRemoved", news.getId()+"/"+news.getHeadline());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildMoved", news.getId()+"/"+news.getHeadline());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.i("YES-Cancelled", databaseError.getMessage());
}
});
When you attach a listener on a particular DatabaseReference it means that the listener will retrieve all data from that location where the reference points to. Because Firebase database doesn't store metadata you need to add a TIMESTAMP for each record yourself. Defining a certain data then you can create a query to filter your database accordingly. Unfortunately, this is a behaviour that cannot be changed in Fireabse.
Assuming you have a node named item and each item within this node has a TIMESTAMP correctly set, the code to query a database using a TIMESTAMP should look like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef.child("item").orderByChild("timestamp");
Further more you can query your database using limitations like this:
Query query = rootRef.child("item")
.orderByChild("timestamp")
.startAt(startingTime)
.endAt(endingTime);
I am getting an error while retriving data from Firebase in Android app.
Error
My code:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = databaseReference.child(path);
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
ClipboardManager clipboard = (ClipboardManager) getApplicationContext().getSystemService(CLIPBOARD_SERVICE);
clipboard.setText(value);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
"path" - child's name.
And my
Your code read all data from the root of your data.
So what you get in the dataSnapshot passed to onDataChange is:
{
"uzmtn": "data"
}
Then you call dataSnapshot.getValue(String.class) on it, which isn't possible: the value in the snapshot isn't a string.
There are two simple options to fix it:
read data lower in the tree
get the correct child from the existing snapshot
I'll start with the second, since it stays closest to your code.
get the correct child from the existing snapshot
Since you're already getting the entire JSON in dataSnapshot, you can use the methods of the DataSnapshot class to find the value you want.
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = databaseReference.child(path);
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.child("uzmtn").getValue(String.class);
ClipboardManager clipboard = (ClipboardManager) getApplicationContext().getSystemService(CLIPBOARD_SERVICE);
clipboard.setText(value);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
While this works, you're reading slightly more data than is needed. It isn't too bad here, but as a general case: it is best to only read the precise data you need.
To do that, we can...
read data lower in the tree
Instead of listening for the root of the database, you can attach a listener straight to the uzmtn node:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("uzmtn");
DatabaseReference ref = databaseReference.child(path);
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
ClipboardManager clipboard = (ClipboardManager) getApplicationContext().getSystemService(CLIPBOARD_SERVICE);
clipboard.setText(value);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
If you do that, the dataSnapshot will contain precisely the string you are looking for:
"data"
And with this in the snapshot, the call to dataSnapshot.getValue(String.class) will work.
You are returning a hashmap type because you didn't specify what child you want to return . Imagine your data structure like a tree in firebase database , each node has its own value .
What you want to return it's the child node from a tree , but instead , you return the node itself , which will return the node itself and the whole child node .
Simple solution is
dataSnapshot.child('emtz').getValue() .....
Explanation -
DatabaseReference Ref;
//intialize Ref variable
Ref = FirebaseDatabase.getInstance().getReference(); //root reference
after this, adding the valueEventListener to Ref
Ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild("abcd")) {
//abcd child is present
}else {
//abcd child is not present
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Now Specifically my question is which algorithm does the firebase using behind the dataSnapshot.hasChild("abcd") ?
In Firebase-database if my root reference contains a huge number of childs then this is an efficient method to use or not?
A DataSnapshot is an efficiently-generated immutable copy of the data at a Firebase Database location. It can't be modified and will never change.
The hasChild(key) can be considered a convenience method for child(key).exists(). As keys are always unique, there is no need to iterate the entire snapshot to locate a specific key, and therefore performance should be something similar to a HashMap at O(1).
If you do have a huge amount of data though, it is often unnecessary to download everything at once, so it's recommended to filter or restrict your query, or select a deeper node and then only obtain a subset of data at a time.
For example, you could listen lower in the tree, for the abcd node directly, and then use the exists() method instead to check for the existence of a child node:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.child("abcd").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
DataSnapshot child = dataSnapshot.child("efgh");
if (child.exists()) {
//efgh child is present
} else {
//efgh child is not present
}
}
#Override
public void onCancelled(DatabaseError databaseError) { }
});
I am storing user details 'firstname' and 'lastname' in UserNode. But when i want to retrieve that details then no data is being retrieved. I tried almost all solutions on the internet but nothing solved my problem. Here is my code for retrieving data of the current user:
FirebaseUser userr = FirebaseAuth.getInstance().getCurrentUser();
if (userr != null) {
String name = userr.getDisplayName();
Log.e("value", name);
}
but it says "println needs a message"
I also tried with this but nothing happened:
DatabaseReference DataRef;
DataRef = FirebaseDatabase.getInstance().getReference().child("UserNode");
DataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String acctname = (String)dataSnapshot.child("firstname").getValue();
Log.e("name", acctname);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
]1
Please help me I am stuck with it
You're reading a collection of user with a ValueEventListener. As the [Firebase documentation for reading lists with a value event](Listen for value events) explains:
While using a ChildEventListener is the recommended way to read lists of data, there are situations where attaching a ValueEventListener to a list reference is useful.
Attaching a ValueEventListener to a list of data will return the entire list of data as a single DataSnapshot, which you can then loop over to access individual children.
Even when there is only a single [child node], the snapshot is still a list; it just contains a single item. To access the item, you need to loop over the result.
So in your code:
DatabaseReference DataRef;
DataRef = FirebaseDatabase.getInstance().getReference().child("UserNode");
DataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String acctname = (String)childSnapshot.child("firstname").getValue();
Log.i("name", acctname);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Using FirebaseUser:
FirebaseUser implements UserInfo and in UserInfo's getDisplayName() documentation says
Returns the user's display name, if available.
So, it is possible that FirebaseUser.getDisplayName() return null when display name is not set. In that case Log.e() receives null as message and therefore prints println needs a message
Using your own structure:
Instead of using type conversion use getValue(Class<T>) like so:
String acctname = dataSnapshot.child("firstname").getValue(String.class);
Please, read how to retrieve data from firebase. I think you have a problem because you don't have Class Model.
Your steps:
Create model UserModel with firstname and lastname field
Use listener (example from docs):
// Attach a listener to read the data at our posts reference
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
System.out.println(post);
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
See other answers: How to retrieve data from one single userID Firebase Android and retrieving data from firebase android
I followed the documentation, but no matter what, I cannot figure out how to return all the objects from a single node. For example, I want to return a list of all company objects from the companies node. Once I have that list, I want to parse them all into JSON objects. This is my first time with a NoSQL database so I'm sure that I'm missing something small.
Currently I have:
DatabaseReference companiesRef = FirebaseDatabase.getInstance().getReference("12265");
companiesRef.child("companies").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("Count ", dataSnapshot.getChildren().toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
But it just returns null for the value: DataSnapshot { key = companies, value = null }.
Here's my database:
You create your reference like this:
FirebaseDatabase.getInstance().getReference("12265");
This means that Firebase looks at the root of the database and returns the child 12265 from under there. It does not automatically search the tree for a node with a matching name.
So you'll need to specify the entire path:
FirebaseDatabase.getInstance().getReference("android/users/12265");
Don't add any parameters to your getReference() (let it go to the root of database) and then set the addListenerForSingleValueEvent. And you have not used getvalue() on you datasnapshot as well. Try this code:
DatabaseReference companiesRef = FirebaseDatabase.getInstance().getReference();
// this is the patch that I see from the image that you have attached.
companiesRef.child("telenotes").child("android").child("user").child("12265").child("companies").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("Count ", dataSnapshot.getChildren().getValue().toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});