This question already has answers here:
How do you prevent duplicate user properties in Firebase?
(2 answers)
Closed 6 years ago.
I am adding username for my Chat App to Firebase Database successfully.
I implemented in activity:
FirebaseDatabase firedb = FirebaseDatabase.getInstance();
in createUser Method.
private void createUser(String uname){
Map<String,Object> newUser = new HashMap<String, Object>();
newUser.put("uname",uname);
DatabaseReference dbref = firedb.getReference();
dbref.child("Users").push().setValue(newUser);
}
When user click a button this method works. This method work correctly but I want to make uname primary key. I do not want to add a username if it is alerady exists.
Database Structure:
Rules:
{
"rules": {
".read": true,
".write": true
}
}
Finally, how to prevent duplicated uname ?
You have to add a top level /uname/ Node. Your data will be like this for example :
{
"Users" : {
"user1" : {
"uname" : "value1",
},
"user2" : {
"uname" : "value2",
},
"user3" : {
"uname" : "value3",
},
},
"uname" : {
"value1": "user1",
"value2": "user2",
"value3": "user3",
}
}
Now you have to Enforce New Data Structure:
{
"rules": {
"users": {
"uname": {
".validate": "!root.child('uname').child(newData.val()).exists()"
},
}
}
}
Related
When launching the following queries by my android app firebase realtime database experiencing abnormal data consumption:
The follow is the first QUERY
final DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference("Linea/Materiale/"+ordine+prodottoPath);
rootRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
.....
qunatitareppNew = f.parse(snapshot.child("quantitarepp").getValue().toString()).floatValue();
...
The follow is the second QUERY
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef2 = database.getReference("Tasks");
Query query2 = myRef2
.orderByChild("idmacrofase")
.equalTo(idMacro);
query2.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot2) {
for (DataSnapshot snap : dataSnapshot2.getChildren()) {
final String idtask = snap.child("idtask").getValue().toString();
.....
I config the follow rule file in firebase realtime database rules:
{
"rules":{
".read": "auth !== null",
".write": "auth !== null",
"Tasks": {
".indexOn": ["idmacrofase","idpick","idrotolo","idtask","lastupdate",".value","dataconsegna","prodotto","checkCS"]
},
"Linea":{
".indexOn":["Materiale",".value"],
"Materiale":{ ".indexOn":[".value","quantitarepp","quantita","ordine"]},
}
}
}
Here i wrote and example of my realtime databese :
.......
"Linea" : {
"Materiale" : {
"300232044211vj01592b226" : {
"ordine" : "300232044",
"quantita" : "4"
},
"300232044211vu01315b205" : {
"ordine" : "300232044",
"quantita" : "4"
},
.....
"Tasks" : {
"101698446" : {
"idmacrofase" : "1620057379ABSI402",
"idpick" : "0030308174",
"idrotolo" : "1620057379ABSI",
"idtask" : 101698446,
"lastupdate" : "1620057379758",
},
how can i change the rules to reduce data consumption?
This question already has answers here:
Query based on multiple where clauses in Firebase
(8 answers)
Closed 4 years ago.
I have firebase like this (I Can't change the table design)
{
"Visits" : {
"-LOyE4h8k218xg-SI2Hy" : {
"Enabled" : false,
"visitorLocation" : "01",
"visitorId" : "22"
},
"-LOyG4__aiiJ3FBVnWbU" : {
"Enabled" : false,
"visitorLocation" : "02",
"visitorId" : "22"
},
"-LOyG5Wyu3cZmZFaCBxY" : {
"Enabled" : false,
"visitorLocation" : "03",
"visitorId" : "22"
},
"-LOyG7gkUj8OFdEsyBGS" : {
"Enabled" : false,
"visitorLocation" : "04",
"visitorId" : "22"
}
}
}
Stored in the firebase,
I would search using visitorLocation and visitorId, and then change the Enabled value.
what i have right now:
DatabaseReference ref =
FirebaseDatabase.getInstance().getReference("visitores");
//This is good, Returns the 4 nodes.
Query q = ref.orderByChild("visitorId").equalTo("22");
q.orderByChild("visitorLocation").equalTo("01").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
dataSnapshot.getChildren().iterator().next().getKey();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
but later i get error: You can't combine multiple orderBy calls!
can anyone help ? how can i search by multiple key values ?
Thank you !!!
You can not use "visitorLocation=04 && visitorId=22 " at the same time but you can modify your table structure by combining these two fields like this "visitorLocation_visitoId=04_22"
To do so you need to add a field in your firebase database table structure so you can apply this AND query
My main goal is to set a RecyclerView item as "favorited" based on a user's previous actions. I'm able to store and delete this data on click, but I'm having difficulty showing it in the right place at the right time.
I have two different nodes that I'm using for this to happen:
"quotes" : {
"0" : {
"Name" : "Foo",
"Source" : "Bar" },
"1" : {
"Name" : "Foo",
"Source" : "Bar" },
"2" : {
"Name" : "Foo",
"Source" : "Bar" }
},
"favorites" : {
"blah#blah,com" : {
"uid0" : "0"
"uid1" : "2" }}}
So basically what I'm trying to do:
Show all the quotes in a RecyclerView, and if their ids show up in the favorites for that unique user, set it visually as favorited. I've included some code here that doesn't seem to be working for me.
private void bindHeart(final ItemHeartCardBinding binding) {
if (inProgress) {
animateProgress(binding);
} else {
binding.favorite.setImageResource(R.drawable.favorite_state_list);
}
//Loop through users favorites to see if current item exists
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference mRootRef = FirebaseDatabase.getInstance().getReference();
String email = "";
if (user != null) {
email = user.getEmail();
email = email.replace(".", ",");
}
final DatabaseReference favoriteRef = mRootRef.child("favorites/" + email);
//quoteKeyStringResId is passed in here as each RecyclerView item is being created. It's the uid of each quote.
final Query queryRef = favoriteRef.orderByValue().startAt(quoteKeyStringResId).endAt(quoteKeyStringResId);
queryRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue().toString().equals(quoteKeyStringResId)) {
binding.favorite.setChecked(checked);
} else {
binding.favorite.setChecked(!checked);
}
}
I dug through the Firebase database samples and found a better way to model my data. Including all the relevant data in the same node allows me to query all at the same time and not have to worry about keeping RecyclerView items in the same order. Things aren't as shallow in this way, but I think that's okay:
"quotes" : {
"0" : {
"Name" : "Foo",
"Source" : "Bar",
//Moved this from a separate node into here
"Favorites" : {
//Each user will be listed if favorited, and removed if unfavorited, making it easy to track and get totals
"userUid" : "true",
"userUid4" : "true" }},
"1" : {
"Name" : "Foo",
"Source" : "Bar" },
"2" : {
"Name" : "Foo",
"Source" : "Bar",
"Favorites" : {
"userUid" : "true" }
}}
My app loads links shared by a user on a listview. I'm trying to load 10-links/posts at a time, and once the user reaches the end query for 10 more links/posts, and so on.
I've denormalized the data, so that once a post is made, its created under "/links" and "user-links/$userId/" by the following code:
String key = mDatabase.child("links").push().getKey();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/links/" + key, postValues);
childUpdates.put("/user-links/" + FirebaseAuth.getInstance().getCurrentUser().getUid() + "/" + key, postValues);
Firebase Data
links
{
"pushId1": {
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309151261,
"link" : https://www.youtube.com/watch?v=bwbwTKXlvQA
},
"pushId2": {
"userId" : zZio89, //userId2
"createdAt" : 1483309145896,
"link" : https://firebase.google.com/docs/database/android/lists-of-data
},
"pushId3": {
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309155525,
"link" : https://firebase.google.com/docs/database/security/indexing-data
}
}
user-links
{
"userId1":
{
"pushId1":
{
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309151261,
"link" : https://www.youtube.com/watch?v=bwbwTKXlvQA
},
"pushId3":
{
"userId" : YuPfsnJD, //userId1
"createdAt" : 1483309155525,
"link" : https://firebase.google.com/docs/database/security/indexing-data
},
},
"userId2":
{
"pushId2":
{
"userId" : zZio89, //userId2
"createdAt" : 1483309145896,
"link" : https://firebase.google.com/docs/database/android/lists-of-data
},
},
}
This is how I currently retrieve the data based on the time its createdAt:
Query myTopPostsQuery = mDatabase
.child("user-link")
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.orderByChild("createdAt")
.limitToFirst(QUERY_LIMIT);
Where; int QUERY_LIMIT = 10;
Firebase Rules
{
"rules":
{
".read": "auth != null",
".write": "auth != null"
}
}
Questions:
1) Once the user reaches the end, how do I skip the first 10 links (which have already been loaded) and load the next 10-links?
2) Is there a way to assign Ascending or Descending order? I would like to show the latest post first.
3) Is firebase-rules ".indexOf" the solution? If so can someone share the exact rule that I must write?
Note: createdAt is generated by the following code while creating the data initially: postValues.put("createdAt", ServerValue.TIMESTAMP );
I'm new to firebase. i'm trying to store some data in Firebase-database in the given format:
approot{
uid{
name:"name"
add:"add"
phn:"phn"
}
uid2{
name:"name"
add:"add"
phn:"phn"
}
.......
and so on.
for this i have written the following code:
String phn = inputPhn.getText().toString().trim();
String add = inputAdd.getText().toString().trim();
String name = inputName.getText().toString().trim();
if (TextUtils.isEmpty(name)) {
Toast.makeText(getApplicationContext(), "Enter name!", Toast.LENGTH_SHORT).show();
return;
}
if (TextUtils.isEmpty(phn)||phn.length()!=10) {
Toast.makeText(getApplicationContext(), "Enter phone no.!", Toast.LENGTH_SHORT).show();
return;
}
if (TextUtils.isEmpty(add)) {
Toast.makeText(getApplicationContext(), "Enter address!", Toast.LENGTH_SHORT).show();
return;
}
//String info="Name:"+name+"\n"+"PhoneNo:"+phn+"\n"+"Adress:"+add+"\n";
String uId=auth.getCurrentUser().getUid();
myref.child(uId).child("name").setValue(name);
myref.child(uId).child("add").setValue(add);
myref.child(uId).child("phone").setValue(phn);
myref.child(uId).child("end").setValue("end");
auth.signOut();
my problem is that i'm getting in-consistent data storage in firebase database. the data stored in database is this :
{
"User" : {
"ANj8GLEJS9alW11QYQyF8Rykwyn2" : {
"add" : "hzjs",
"name" : "hxjx"
},
"b0ZBftQ5UOOtTtzkeZHcC0558MC3" : {
"add" : "gw",
"name" : "hs"
},
"eH6rCXzvEncTe163N7KaJ7XEZp52" : {
"name" : "dudj"
},
"gEqc92Z0mvcfIWvhZu7QOhRcnNQ2" : {
"add" : "bsus",
"name" : "jziz",
"phone" : "1234567890"
},
"kGF2PalHrpeFus6682z55p47YBg2" : {
"add" : "hdud",
"name" : "jdhd"
},
"nHRt5n5roGfU3QogVUM09HDBrIw2" : {
"add" : "qwerty",
"end" : "end",
"name" : "q",
"phone" : "1234567860"
},
"pRRzexjQN1eynoCQcoClNl2TcHk2" : {
"add" : "dvjh",
"name" : "rhid"
},
"vaek3Z4eEVTWmc722T92tfgBwaE3" : {
"add" : "dhudvj",
"name" : "gsbud"
},
"xsH5JoTXftaxicUmvntt0N5hcNJ3" : {
"add" : "zhs",
"name" : "q"
}
}
}
please help me.
Edit
i'm using firebase 9.2.1.
and the rules defined are:-
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
You should wait for the setValue to finish before you sign out the user, because the auth will be null after the signOut successfully called. If the setValue haven't finished, it will violate your rule because the auth has been null.
You can use a CompletionListener to make sure that the setValue is completed, then you can safely sign out the user. Like this
Map<String, String> values = new HashMap<>();
values.put("name", name);
values.put("add", add);
values.put("phone", phn);
values.put("end", end);
DatabaseReference.CompletionListener completionListener = new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
auth.signOut();
}
};
myref.child(uid).setValue(values, completionListener);