I have a collection of groups and a collection of users, each user document has a collection of ids to the group he has joined. each group id document has one field (timestamp) to mark when a user joined a group.
I want to get the list of groups the user has joined in ordered by timestamp descending.
First I am getting the groups ids from the sub collection inside user document and they are ordered by timestamp, Then, I am using whereIn() to get the groups objects from the groups top level collection by passing 'groupsIds' ArrayList.
Here is the problem, resulted documents from whereIn() are randomly ordered. I want them to be ordered according to 'groupsIds' list. Can firestore do that for me ? Or I will have to do this myself ?
If you can't tell Firestore how to sort the documents using orderBy, you're going to have to sort the documents yourself. And in this case, you are going to have to do that.
Related
Goal: show the list of groups based upon the recent message and when a new message comes, update the chat group list.
Firebase Structure:
Left one structure represents user model: Basically under student key, there is a list of the student then its details along with group ids in which he/she participated.
Right one structure represents the group detail model: Under chat_group key, there is a list of groups with details and also recent message timing.
Solution Tried:
Fetch the group id from the student using the onChildAdded method of firebase DB one by one then fetch its group details using the addListenerForSingleValueEvent method, then store in the list and every time sort it using sort method of array list and then call notifyDataSetChanged method of recyclerview adapter.
Problem with this approach: Too time-consuming and as the number of groups increases processing time also increases.
I think the best solution is to add a new key to the group details model for the students signed up , like that
SignedStudents : "student1 , student2 , student3"
Then you will read data from chat_group directly orderedByChild("recent_message_timeStamp") , then you have to filter it locally to get the groups only related to the specific student to add it to your list like that
String students = model.getStudents();
if (students.contains("student1")) addGroupToYourList();
In my database:
-Users(Top level collection):
---user1(doc):
----------pets(sub collection):
--------------pet1(doc)
--------------pet2(doc)
---user2(doc):
----------pets(sub collection):
--------------pet3(doc)
--------------pet4(doc)
If i have a List of ids: list("pet2", "pet3", "pet4)
Is there a way to do something like this and get a back a List of DocumentsSnapshots?
firestore.collectionGruop("pets")whereIn(FieldPath.documentId(), list)
It works with a root collection but i dont know if this is possible with a collection group
A collection group query is the only place where a filter on FieldPath.documentId() does not work the way you expect. That's because of some details about the way that this token actually works. If you try to this anyway, you will get an error like this:
Invalid query. When querying a collection group by FieldPath.documentId(), the value provided must result in a valid document path, but 'x' is not because it has an odd number of segments.
If you want to do a filter on document IDs in a collection group query, you will need to store the ID of the document as the value of a field in each document. If you use the field called "id", then you can filter on that field like this:
firestore
.collectionGruop("pets")
.whereIn('id', list)
This will give you a different error saying that you need to create an index, and give you a link to do so. After you create that index (it might take some time), you should be good to go.
See also: How to perform collection group query using document ID in Cloud Firestore
This question already has an answer here:
Firebase query if child of child contains a value
(1 answer)
Closed 3 years ago.
I need a firebase query to filter the list based on the value of an array.
if any of the index of GID(Array) contains the given key. e.g my key is YsGMyfLSGRNHxDWQmhpuPRqtxlq1 and one node's GID have that on 0th index and other have that on 1st index. So these two lists need to be returned.
Currently, I can only get the one at 0th index using the code
//userID = YsGMyfLSGRNHxDWQmhpuPRqtxlq1
firebaseDatabase.child("Groups").queryOrdered(byChild: "GID/0").queryEqual(toValue:userID)
When I try to combine the query I am getting errors.
I don't know about your database structure, But I can explain that There is a limitation in Firebase Realtime database that you can only order by 1 child.
So now if we require to order by 2 Childs we can combine 2 nodes and make it 1 node and can apply order by query on it. For example
If we have username & email fields we can make a new field username_email and can apply order by on it.
Like
user: {
username: "john",
email: "john#g.com"
username_email = "john_john#g.com"
}
Now we can write
firebaseDatabase.child("user").queryOrdered(byChild: "username_email").queryEqual(toValue: "john_john#g.com");
There is no way you can filter your groups based on a value that exist within an array. If you want to query your database to get all groups a particular user is apart of, then you should consider augmenting your data structure to allow a reverse lookup. This means that you should add under each user object the groups in which that user is present.
This means that you'll need to duplicate some data, but this is not a problem when it comes to Firebase. This is a quite common practice, which is named denormalization and for that, I recommend you see this video, Denormalization is normal with the Firebase Database.
When you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.
However, what you need is actually allowed in Cloud Firestore. Its array-contains operator allow you to filter documents that have a certain value in an array. For more on this topic, please see the following post:
Better Arrays in Cloud Firestore.
I have a users collection with uId, name, photo
I have a visits collection with uId, userId, location
I have a recyclerview in which I want to show the location with the user name and photo
Can I use the reference field type? If so, how will Firestore know to link visits.userId == users.uId ?
Maybe I first need to query all the visits and then query the relevant user but 2 things:
It means querying a lot of times.
I didn't understand how to collect the joined collection into the adapter, which is based on one query?
Please advice
Thanks
current code
visitsList = db.collection("visitsList");
Query query = visitsList.whereEqualTo("userId",prefs.getString("id","")).orderBy("visitDate", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<AVisit> options = new FirestoreRecyclerOptions.Builder<AVisit>().setQuery(query, AVisit.class).build();
adapter = new VisitsListAdapter(options, VisitsListActivity.this);
RecyclerView rv = findViewById(R.id.rvVisitsList);
rv.setHasFixedSize(true);
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(adapter);
The code is a simple query from the collection, not sure how to get the name and photo from the userId field in that collection.
Can I use the reference field type?
Yes, you can use a reference field.
If so, how will Firestore know to link visits.userId == users.uId ?
Firestore results always comes from a single collection (at the moment). It does not automatically join the document from the users collection when you're reading from the visits collection. You will have to do this yourself.
That indeed means you'll be executing multiple reads, but it's often not nearly as slow as you may think. See Google Firestore - how to get document by multiple ids in one round trip?
Update: To show data from the user profile in a list of visits, there are two main options:
load the additional user document in populateView or with a custom parseSnapshot implementation.
duplicate the relevant user data in the visits collection (which is quite normal in NoSQL databases). Also see Alex' answer here: indexed query with FirestoreRecyclerAdapter.
I want to create an application that any user can add an advert (announce) with something that he wants to sell.
This is the structure of the Real-time Database in Firebase:
- advert
- category
- {uid}
- title
- price
- description
- location
I want to let the user to filter the adverts by category, title, and price.
Currently, I can filter the adverts only by title like this:
FirebaseDatabase.getInstance().getReference()
.child("adverts")
.orderByChild("title")
.startAt("tv")
.limitToFirst(20)
I have 3 questions:
How can i add more "and clauses"? Or how should i structure the nodes to filter more values?
How should I sort the values that i receive from the server in ascending order or descending order depending on uid?
Seems that the method startAt("abc") is not fetching only the children that has contains in the title "tv". Am i doing something wrong? How should I fetch only the children that contains the string "tv"?
On firebase, there is no way to add "AND clauses". You must structure your data in a way that matches your filtering needs.
I believe firebase already sorts the data by uid.
If you want to fetch only the children that contains the string "tv", you should use this query:
FirebaseDatabase.getInstance().getReference().child("adverts").orderByChild("title").startAt("tv").endAt("tv").limitToFirst(20);
I suggest that you watch the Firebase Database for SQL Developers Series. It has the answers for the 3 of your questions