This question already has an answer here:
How to create auto incremented key in Firebase?
(1 answer)
Closed 4 years ago.
I want to append a String to my List on the Firebase Realtime Database.
(My code already works but there is a problem)
So the Database looks like this:
message:
0: "some string"
1: "another string"
2: "some string"
But I think the problem with this code would be, that if somebody reads the numbers of messages and then wants to write a message there would be a problem, when another user writes a message in the mean time (because the number of messages would change).
FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myRef = database.getReference("message");
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
myRef.child(
String.valueOf(dataSnapshot.getChildrenCount())
).setValue("SOME STRING");
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Trying to use sequential numeric indexes (also often referred to as array indexes or auto-increment values) in a multi-user Firebase is an anti-pattern for a few reasons.
As you've already noted yourself, there's a chance of users overwriting each other's data. This is fixable however by using a transaction, which is the way to go if you need to property a value based on its existing value. The reference documentation for the JavaScript DatabaseReference.transaction method have this example that is pretty much what you need:
// Increment Ada's rank by 1.
var adaRankRef = firebase.database().ref('users/ada/rank');
adaRankRef.transaction(function(currentRank) {
// If users/ada/rank has never been set, currentRank will be `null`.
return currentRank + 1;
});
The syntax in Android is slightly more involved, but would work the same.
While a transaction works, this means that the application will only work when the user is connected to the server. When they're offline, the transaction will fail.
For these reasons Firebase apps typically use a different mechanism to generate their keys. The built-in push() method of the API generates a unique, always-incrementing key. While this key is not as readable as your sequential, numeric keys, they do address both of the above problems without the need for you to write more code for it yourself. With push() adding a message becomes as simple as:
final DatabaseReference myRef = database.getReference("message");
myRef.push().setValue("SOME STRING");
Note that this topic has been covered quite a bit already, so I recommend also checking out:
Best Practices: Arrays in Firebase
The 2^120 Ways to Ensure Unique Identifiers
How to create auto incremented key in Firebase?
Auto-increment a value in Firebase (has the transaction code for Android)
how do i auto increment a value in firebase
Related
This question already has an answer here:
How to create auto incremented key in Firebase?
(1 answer)
Closed 4 years ago.
I want to append a String to my List on the Firebase Realtime Database.
(My code already works but there is a problem)
So the Database looks like this:
message:
0: "some string"
1: "another string"
2: "some string"
But I think the problem with this code would be, that if somebody reads the numbers of messages and then wants to write a message there would be a problem, when another user writes a message in the mean time (because the number of messages would change).
FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myRef = database.getReference("message");
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
myRef.child(
String.valueOf(dataSnapshot.getChildrenCount())
).setValue("SOME STRING");
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Trying to use sequential numeric indexes (also often referred to as array indexes or auto-increment values) in a multi-user Firebase is an anti-pattern for a few reasons.
As you've already noted yourself, there's a chance of users overwriting each other's data. This is fixable however by using a transaction, which is the way to go if you need to property a value based on its existing value. The reference documentation for the JavaScript DatabaseReference.transaction method have this example that is pretty much what you need:
// Increment Ada's rank by 1.
var adaRankRef = firebase.database().ref('users/ada/rank');
adaRankRef.transaction(function(currentRank) {
// If users/ada/rank has never been set, currentRank will be `null`.
return currentRank + 1;
});
The syntax in Android is slightly more involved, but would work the same.
While a transaction works, this means that the application will only work when the user is connected to the server. When they're offline, the transaction will fail.
For these reasons Firebase apps typically use a different mechanism to generate their keys. The built-in push() method of the API generates a unique, always-incrementing key. While this key is not as readable as your sequential, numeric keys, they do address both of the above problems without the need for you to write more code for it yourself. With push() adding a message becomes as simple as:
final DatabaseReference myRef = database.getReference("message");
myRef.push().setValue("SOME STRING");
Note that this topic has been covered quite a bit already, so I recommend also checking out:
Best Practices: Arrays in Firebase
The 2^120 Ways to Ensure Unique Identifiers
How to create auto incremented key in Firebase?
Auto-increment a value in Firebase (has the transaction code for Android)
how do i auto increment a value in firebase
I am having an app which writes in firebase and I want my another app with admin privileges to read and edit the data present in the custom key
If this is the picture assume where a random key a my key and I want to edit the data or add new data with the present data in that particular custom key.
Any help will be appreciated
Not 100% sure what you're asking, but if you want to get all the children, do:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("yourTable");
ref.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// All your data is in dataSnapshot
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
}
);
If you want to set a specific child's value by the key do:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("yourTable");
ref.child("mySpecificChildId").child("message").setValue("new value");
If these don't help, please add a more specific question!
If these keys are auto generated and you cannot get a hold of them, it does not matter what privligies you have you cannot get them.
However, if you do have the key, or getting it from a function, and you want to change the values at the specific node or just read them you can just query the database for that key and change it after wards something like this:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference mRef = database.getReference().child("YOUR KEY");
and then you can access read and edit the values at the node
mRef.child("message") //Do Whatever you want
PS: just make sure you are checking if the dataSnapshot Exits!
EDIT:
if your first app is the one generating the keys, you can store them in a different node and access that node based on position to get the key and after you make sure you accessed that node just query for the key
I am making a challenges between users in my app .I am trying to get the last 15 users who enters in challenges. I store the time each time the users enter a new challenge. The query was working well in the begging but after that it stops showing new users and only old users appears in it.
this is the query code :
usersReference.orderByChild("lastChallengeDate")
.limitToLast(15)
.addListenerForSingleValueEvent(new ValueEventListener()
and this is the database structre of the user child :
When I opened the log I found this warn although I am using index on in my rules
W/PersistentConnection: pc_0 - Using an unspecified index. Consider adding '".indexOn": "lastChallengeDate"' at users to your security and Firebase Database rules for better performance
If you perform a query on a location, Firebase sorts the children under that location on the property you specify. There is no value in lastChallengeDate directly under each child of users. Instead the property is under lastChallengeDate/time, so you should order on that
usersReference.orderByChild("lastChallengeDate/time")
.limitToLast(15)
.addListenerForSingleValueEvent(new ValueEventListener()
You also need to define an index on users (or whatever the name is of the node you query):
{
"rules": {
"users": {
".indexOn": "lastChallengeDate/time"
}
}
}
Be sure to also study:
the documentation on queries, which includes an example of querying such a nested property
the documentation on defining indexes
some of the many questions with the same error message
I am an experienced MySQL user but I am a newbie to json and firebase. I am trying to make an activity where a user is able to enter data and I save it to my db in firebase. I achieved my goal but here is the problem. When I save it(I think) I need to specify a child element with a string. Since this child element is static,every time a user enters a question it overwrites the existing one in my database. How can I fix this and how can I get the data back? Here is that part of my code.
private FirebaseAuth firebaseAuth;
private DatabaseReference databaseReference;
firebaseAuth=FirebaseAuth.getInstance();
if(firebaseAuth.getCurrentUser()==null){
finish();
startActivity(new Intent(this,LoginActivity.class));
}
FirebaseUser user=firebaseAuth.getCurrentUser();
databaseReference= FirebaseDatabase.getInstance().getReference();
Info info=new Info(question,answer,a,b,c,d);
databaseReference.child("secondQuestion").setValue(info);
//info is a new object which takes 6 string as an input.
// As you can see, I declare a string inside .child and it overwrites the data stored in it
As Andrew commented, it is indeed normal to add items to a (semi-chronological) list using push.
They're logically similar to a auto-increment field in MySQL, but have a (very) different format. See this post about why Firebase doesn't use the +1 style increments and this post on the push IDs.
If your questions already have a property that uniquely identifies them, you should probably use that as the key. So say that you're storing a list of Firebase Authentication users, you'd store each user under their uid. Or if the question text must be unique, you should probably store each question under (a hashed derivative of) their text.
Noob here.
Trying to see if a DatabaseReference exists in my database. Here is how I do it:
String key = "ABCDE";
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("itemIds").child(key);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snap) {
if (!snap.exists())
tellUserThatItDoesntExists();
else
tellUserThatItExists();
}
.....
}
But the code always results to the reference not existing even though a node root/itemIds/ABCDE (which is BTW, I added through the Firebase console) does exist in the database.
All of the data is public, so there is no reason for me to not be allowed to read data.
Edit: Here is a screenshot of the visual tree of the database. Everything here (except the meh node) was saved using Firebase console:
Another edit: Did some fiddling around and apparently, based on my observation, Firebase can't seem to read data that were added by the console. I have come up with this conclusion because I made the program I'm working on write something to the database and tried to check if that exists and it works fine.
Any idea on how to solve this issue?
Ok so the reason for this error is obvious from your snapshot.
Don't save data with - " " quotes! Firebase reads the data added from console just fine. But if you are adding quotes then you have to refer as - .child(""itemIds"")
Hope this helps. Remove the quotes and firebase will read it. Only the value for key can have quotes. Check the meh node how it is formatted. That is the correct way.