Below is image representation of my firebase where user upload items under Electronics or Books category and also more categories. I want to build an activity with RecyclerView where I want to show the only item uploaded by a user. Since I'm using userid which is unique to push the details of the item inside a child, I can use userid to retrieve the items from child and display in firebase. But, how to search in each child from different category and show it in one RecyclerView.
My Code to Show the items from Electronics child is
dbreference = FirebaseDatabase.getInstance().getReference("Electronic").child("userid");
dbreference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.exists()) {
for (DataSnapshot data : snapshot.getChildren()) {
final Solditem b1 = data.getValue(SoldItem.class);
child_count++;
list.add(b1);
staggeredBooksAdapter.notifyDataSetChanged();
}
}
}
But I also would like to show the uploaded item by a user which equals to userid as key from Books in the same RecyclerView.
To delete an item from any category I use
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Query sellerquery = ref.child("Electronic").child("userid");
sellerquery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot appleSnapshot: dataSnapshot.getChildren()) {
appleSnapshot.getRef().removeValue();
}
}
}
To delete all the records of a user-uploaded item which key-value equals to userid, I need to repeat above code.
Is there any best and short method to delete all the records from any category which key-value equals to userid.
Thanks in advance.
While structuring your data in Firebase, you really need to think about the structure of your data very carefully so that you can run efficient queries on them. For example, in your case, you should have structured your data as follows.
userid
- Electronics
- Camera
- Cooker
- Books
- A brief history of time
- Inferno
Hence you could run your queries in such a way that, you could have all the items under a certain userid at once.
If you really need the structure that you have now for other sets of queries that you are planning to do in your application, think about replicating your data as well. That is, you might consider having duplicate entries of your data (replication) in different structure so that you can perform efficient queries. For example, the current structure of your data is suitable for the following query.
Get all userid under a specific category.
I think you have got my point. If you do not want to change the structure of your data then I am afraid that you might have to get all the data in your application from firebase first. Then you have to loop through the data yourself to find the elements that you actually needed.
Hope that helps!
Related
private void RetrieveAndDisplayGroups() {
FirebaseRecyclerOptions<GroupModel> options = new FirebaseRecyclerOptions.Builder<GroupModel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("Groups"), new SnapshotParser<GroupModel>() {
#NonNull
public GroupModel parseSnapshot(#NonNull DataSnapshot snapshot) {
// I tried to use if statment before return.
return new GroupModel(snapshot.child("groupName").getValue().toString(), snapshot.child("groupDescription").getValue().toString());
}
}).build();
modelAdapter = new GroupModelAdapter(options, getContext());
recyclerExploreGroupView.setAdapter(modelAdapter);
}
So I am making a group chat app.
In my app, I want to show the users only the groups they have created.
In the database, under node "Groups", I have all the groups created by all users.
I am using firebase recycle adapter to retrieve data from firebase real time database.
I am not familiar with how FirebaseRecycleOptions work. I think it returns a set of the model object I passed.
I try to use if statement before new firebaseRecycleOptions return. But I got red line.
The goal is to check if each group has a child as a requirement. And only retrieve the ones who have it.
Any help would be appreciated.
If you want to only show a subset of the child nodes in the adapter, you should use a query to retrieve only those child nodes from the database.
It's hard to be certain without seeing your database, but using this query in the adapter might be an option:
FirebaseDatabase.getInstance().getReference()
.child("Groups")
.orderByChild("groupName")
.startAt(null)
Since null is the first value in Firebase Realtime Database ordering, this will return any node that has a groupName value.
Preface:
For this question to make sense, I need to describe my intent for the database. It will be used to store user data based on a grid of latitude and longitude sectors created by finding the floor value of the exact coordinates of the user when they sign up or log in. The reduced coordinate values are then concatenated, saved in shared preferences on the user's phone, and then set as the primary nodes in the database. This allows searching through the database to be restricted to just the sector the user is currently in which is required by a feature of the app. See the example the nodal layout of the database below:
The Problem:
This system works great, except for that when the user logs in on a new device (or if the shared preferences are lost) from outside the original sector, or from the previous sector, there is no way to know the previous or original sector value.
The Answer:
The answer I came up with is to search every single sector node in the database for the unique uid easily acquired by the following code:
FirebaseAuth mAuth = FirebaseAuth.getInstance()
String currentUser = mAuth.getCurrentUser().getUid();
However, I don't know how to search through every single node (of which there may be thousands because there are thousands of potential sectors) in the database for a particular child. Note that every primary node has a different name, but they all contain the child "users" which can then hold any number of child "uids."
Once the current uid is found in the previous sector-node, my intent is to transfer all of the children of the current uid in the previous sector to the new one. I want to avoid iterating locally through the entire database for the uid as well.
private DatabaseReference userRef = FirebaseDatabase.getInstance().getReference();
mLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String email = mEmail.getText().toString();
final String password = mPassword.getText().toString();
final String currentUserId = mAuth.getUid();
mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
Toast.makeText(LoginActivity.this, "sign in error", Toast.LENGTH_SHORT);
} else {
if (task.isSuccessful()){
userRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
})
}
}
}
});
}
});
All this needs to occur after the success of a sign-in event as shown above. I have a feeling I need to use a dataSnapshot for this but I am unsure. I also read another post and considered the following to be the start of something that might work, but I don't know:
Query searchQuery = userRef.child("Users").equalTo(currentUserId);
The flow of the query should be this: Search first node -> Navigate to Users --> iterate through for currentUid --> If currentUid is not found Search the second node... and so on and so forth until the currentUid is found.
If anyone has the answer or any suggestions, guidance, or hints, I would be very grateful. Thank you.
A Firebase Database query can only contain one unknown level in the path. Your current structure doesn't allow you to search all sectors for a specific user. You can search across all users in a single section, but not across sectors.
So while your current code makes it easy to find all users in a specific sector, or even range of sectors, it doesn't make it easy to find the sector for a specific user. To allow the latter use-case you'll need to add an additional data structure for that purpose. Typically something like:
"user-locations": {
"$uid": "
"sector": "37-123",
"location": "..."
}
}
So this means that when a user moves, you'll need to update their location in two places.
This sort of data duplication is common in NoSQL databases, where you need to update your data model to allow the use-cases. It is also quite common to have more complex write operations, in order to make read operations simpler and more scalable.
For more on this, see my answers to:
Firebase Query Double Nested
Firebase query if child of child contains a value
And:
NoSQL data modeling
Firebase for SQL developers
I'm using push() method to create unique ids for database but when I create an id with push method its added to bottom of tree but I want it to be on top. How can I do that?
For example in this picture bottom one is newest one I want it to be on top. How can I do that?
Picture
I want this because I use RecyclerView with Firebase adapter and adapter start to read from top.
edit: how to get data from bottom to top from firebase?
This question is what I want but there is no useful answer.
I'm using push() method to create unique ids for database but When i create an id with push method its added to bottom of tree but i want it to be on top
When you are using the push() method, the objects in the Firebase Console are ordered chronologically and unfortunately there is nothing you can do about it. This order cannot be changed. If you want to display the items from the datababse in a RecyclerView and hypothetically speaking, you would have been able to change the order in the console, it doesn't mean that this order is the same with order in the RecyclerView. To display your items in a particular order, I recommend you to use a Query and sort them according to a timestamp property. For that, please see Frank van Puffelen's answer from this post and if you are using the Firebase-UI library, please see my answer from this post.
you can write a simple query to get data as you need it
add date parameter to your object then query the data by the date
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child("data").orderByChild("date");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
// fill recyclarView with data
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Image here. Data does not sort accordingly like I wanted (O+, O+, A)
Currently, I have data that stored exactly like in the picture above, I want to make all the blood groups to be placed accordingly. For example, It will have only 0+ until the lists end. It will continue with different blood groups such A+, A- etc.
Can firebase actually sort that data? I was looking around, but could not find anything
Inside the Firebase Console, all the nodes are sorted lexicographically by key and this can't be changed.
However, when you retrieve the data on the client, you can choose to sort by one of the child properties. This way they will be sorted by the time they are shown to the client. For example:
// the reference to where your people are stored
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
// create the query
Query peopleBloodTypeQuery = mDatabase.child("people").orderByChild("bloodgroup");
// query the people
peopleBloodTypeQuery.addChildEventListener(new ChildEventListener() {
// add a child added listener
#Override public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
// do whatever here - I just print the key of each added child
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
}
});
CONTEXT :
Hi, I'm currently working on an Android project backed by Firebase.
I have set up a denormalized data structure that relates polls to users (many-to-many relationship) via way of votes. Here is an image displaying the votes path of my database. The structure is as follows :
votes -> [pollUid] -> [votePushuid] -> vote object
So in this example we have a single poll that has 4 votes.
I want to run a check to see if a user has already voted on a poll. In order to do this I fetch the pollsUid, then run through its votes to see if any of them contain the voterUid property == to their user uid.
This is done as follows :
FirebaseHandler.getInstance().getMainDatabaseRef()
.child(FirebaseConstants.VOTES) //votes root
.child(pollKey) //polluid
.orderByChild("voterUid")
.equalTo(FirebaseHandler.getInstance().getUserUid())
.limitToFirst(1)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.exists()) {
If the datasnaptshot exists then we know that the user has already voted on this poll and can handle it in the Java logic.
PROBLEM :
The datasnapshot received by onDataChange is always null (ie does not exist) when searching for a specific user's vote on a specific poll. I know for a fact that the vote exists in the db through inspecting the data, and that the userUid is correct via debugging. Removing the equalTo and limitToFirst returns all of the votes for the poll without a problem so clearly the stem of the ref is correct. This implies to me that the issue is created by one of the two methods just mentioned. Even stranger is the fact that this approach does work at certain times, but not at others.
QUESTION :
How do I return a list of firebase stored objects filtered by a grandchild property? If this is not possible what would be the more appropriate datastructure for this problem?
On a further note I've seen people taking the approach of using Query instead of Databasereferences. Perhaps this might have something to do with the current issue.
Your query is correct. I have no problem running that query using my own DB. It's probably the userId doesn't match. DatabaseReference extends Query, that's why you can access Query's methods.
A database structure alternative would be
{ "users_votes": {
"<userId>": {
"<pollId1>" : true,
"<pollId2>" : true,
"<pollId3>" : true
}
}
}
Set the value to that node once the user voted to a poll.
To check if the user has voted for a poll
usersVotesRef.child(FirebaseHandler.getInstance().getUserUid())
.child(pollKey).addListenerForSingleValueEvent(valueEventListener);