My DB :
I create new item like this:
mFirebaseDatabase.getReference(Api.CREDITS).child(String.valueOf(item.getId())).setValue(item);
but when I'll create a new item , I need to set his ID... how to determinate last id of items in the list in Firebase?
The easiest way is probable:
var latest = ref.child("credits").orderByKey().limitToLast(1);
latest.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String latestKey = childSnapshot.getKey();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled", databaseError.toException());
}
})
But this is going to lead to problems like:
this operation will not work when the user is without network connectivity
when multiple users are trying to add children at (almost) the same time
This is one of the many reasons why Firebase recommends against using such sequential numeric IDs and uses push IDs.
Read the documentation on dealing with lists and this blog post: https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html
Related
Here is my Database architecture where Jobs is the main child and under that there will be users child, and an user can post multiple time. now i want to get all the posts done by all the users at once. is it possible to do that?
https://i.stack.imgur.com/DT3MO.jpg
setQuery(FirebaseDatabase.getInstance().getReference().child("Jobs")
Used that query to get all of the posts from all of the users but didnt work. any better solution for this problem?
setQuery(FirebaseDatabase.getInstance().getReference().child("Jobs").child("Uid");
this one works but cant use this one because i want to set free for all users to read data.
You can do the following:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Jobs");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
String key = ds.getKey();
for (DataSnapshot childSnapshot: ds.getChildren()) {
// get the child attribute under the random key
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
Since you have a reference to node Jobs then in the first iteration you can get the random keys (highlighted in your image), and in the second iteration you can get the attributes inside those keys.
Please check my database image. I want to select and display all users who have parent = chris
my database image
To retrieve the users that contain parent : chris, you can do the following:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("users");
reference.orderByChild("parent").equalTo("chris").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot datas: dataSnapshot.getChildren()){
String name = datas.child("name").getValue(String.class);
String key = datas.getKey();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
orderByChild.equalTo is a query that will retrieve all the nodes that contain parent equal to chris.
Since you tagged this as a android studio question I assume you are using the Firebase SDK.
You should check out the documentation, where they explain how you can query in a lot of languages with very nice examples.
CABARAN is an unknown Uid. it is not a text. Right now I have the uid, and I want to get value for the tajukPenuh.
This is the code and I still can't get the value.
FirebaseDatabase.getInstance().getReference().child("karangan").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Karangan karangan = child.child(karanganID).getValue(Karangan.class);
if (karangan != null) {
String tajukPenuh = karangan.getTajukPenuh();
holder.getTextViewKaranganID().setText("Karangan Tajuk: " + tajukPenuh);
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
You could in theory do a query like this:
FirebaseDatabase.getInstance().getReference().child("karangan")
.orderByChild("-LYgFIl4Xiv_Ls51Slvh/uid").equalTo("-LYgFIl4Xiv_Ls51Slvh")
.addListenerForSingleValueEvent(new ValueEventListener() {
But the problem is that you'd need a lot of indexes in your rules, which may be technically possible, but is unfeasible for most real usage.
Your current data structure makes it easy to find all the child nodes for CABARAN, but it does not make it easy to find CABARAN for a given child node. To allow that use-case to run efficiently, you should expand your data structure with a so-called reverse index that maps back to CABARAN from the value that you know. So something like:
"myIndex": {
"-LYgFIl4Xiv_Ls51Slvh": "CABARAN",
"-LzfFIl4Xasas51Slads": "CABARAN",
"-Lasddas981398asdh1h": "CASITWO"
}
This is an additional data structure, that you will have to keep up to date when you're writing the rest of the data. But with this structure, it now becomes very easy to determine that -LYgFIl4Xiv_Ls51Slvh maps to CABARAN.
For more on this, see my answer here: Firebase query if child of child contains a value
my data look like this
and I simply want to add an object at index 3. How could I add it there. Is there any way to add an object without iteration or I have to iterate and getChildCount and then append new child("3") and it's data to it.
TransGenderBO transGenderBO = new TransGenderBO();
transGenderBO.setName("pushName");
transGenderBO.setAge(13);
mRef.child("").setValue(transGenderBO);
there is no method in mRef for getting child count and appending new item at 3 position..
Edit after using Frank code but still not working
Query last = mRef.orderByKey().limitToLast(1);
last.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int lastIndex = 0;
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
lastIndex = Integer.parseInt(childSnapshot.getKey());
}
TransGenderBO transGenderBO = new TransGenderBO();
transGenderBO.setName("pushName");
transGenderBO.setAge(13);
mRef.child(""+(lastIndex+1)).setValue(transGenderBO);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(mContext,databaseError.getMessage(),Toast.LENGTH_LONG).show();
}
});
There is a good reason that the Firebase documentation and blog recommend against using arrays in the database: they don't work very well for multi-user applications where users can be offline.
To add the next element to your array here, you'll have to download at the very least the last element of the array to know the index of the next element:
Query last = root.orderByKey().limitToLast(1);
last.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int lastIndex;
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
lastIndex = Integer.parseInt(childSnapshot.getKey());
}
root.child(""+(lastIndex+1)).setValue(true);
}
But this has an inherent race-condition. When multiple users are adding elements to the array at the same time, they may end up writing to the same index.
To prevent this you can use a Firebase transaction. With this you get the current value from a location and in exchange return the new value you want at that location. This ensures that no data is overwritten between users, but means that you have to download the entire array.
And neither of these scenarios works when a user is not connected to the network.
Firebase instead recommends using so-called push IDs, which:
Generate a always-increasing key that is guaranteed to be unique.
Do not require reading any data - they are generated client-side and are statistically guaranteed to be unique.
Also work when a user is offline.
The only disadvantage is that they're not as easily readable as array indexes.
Get your data like this
private ArrayList<TransGenderBO> transGenderBO;
FirebaseDatabase.getInstance().getReference().child("Main")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
transGenderBO = (ArrayList<TransGenderBO>) dataSnapshot.getValue();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
and set your value like this
TransGenderBO transGender = new TransGenderBO();
transGender.setName("pushName");
transGender.setAge(13);
FirebaseDatabase.getInstance().getReference().child("Main").child(String.valueOf(transGenderBO.size())).setValue(transGender);
or U can set this way too
TransGenderBO transGender = new TransGenderBO();
transGender.setName("pushName");
transGender.setAge(13);
TransGenderBO.add(transGender);
FirebaseDatabase.getInstance().getReference().child("Main")
.setValue(transGenderBO);
Description
My Firebase NoSQL Database should look somewhat like this:
A user Java model should get pushed whenever a new user signs in.
Problem
How to check if the user with the email address already has an account? Since the email address is at: Root > PushID > email; and push ID is automatically generated, I am not sure on how to iterate on all push ID's and check if any of them has its email key set to the specified value.
I have read the documentation but unable to figure out how to solve this problem.
Learning from Shubhank's answer
Firebase Methods which involve a child can be applied to any of its children irrespective of its level in the hierarchy i.e. not limited to immediate children.
In this problem, the child to be searched was 2 levels below the common parent. The first level child can be ignored and query methods can be directly applied on the target child.
You should first make a model class for the user
class User {
public String email;
public String name;
}
Then get the users from the db and map them into User objects
Simple loop through all results query
FirebaseDatabase database = FirebaseDatabase.getInstance();
// i don't know the end point since you have not specified it in the image
database.getReference("myUsersEndPoint").addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot data : dataSnapshot.getChildren()) {
User user = data.getValue(User.class);
if (myField.getText().toString().eqaulsIgnoreCase(user.email)) {
// exist
}
}
}
#Override
public void onCancelled(DatabaseError databaseError)
Log.w("MyApp", "getUser:onCancelled", databaseError.toException());
}
});
Searching only for specific Values
In this example, we use the orderByChild and equalTo method to limit result to specific child value
FirebaseDatabase database = FirebaseDatabase.getInstance();
// i don't know the end point since you have not specified it in the image
database.getReference("myUsersEndPoint").orderByChild("email").equalTo("emailToSearchhere").addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot data : dataSnapshot.getChildren()) {
// here the user will have the specified email only
}
}
#Override
public void onCancelled(DatabaseError databaseError)
Log.w("MyApp", "getUser:onCancelled", databaseError.toException());
}
});