Firestore: Order by sub-collection field - google-cloud-firestore

First of all, this is not a regular question. It's little complicated.
App summary
Recipes app where users can search recipes by selected ingredients (collection ingredients exists in firestore db). I want to store for every ingredient statistics how much did users search with that selected ingredient, so I can show them later at the top ingredients which they used mostly for searching recipes.
This is how my collection looks like:
http://prntscr.com/nlz062
And now I would like to order recipes by statistics that created logged in user.
first = firebaseHelper
.getDb()
.collection(Constants.INGREDIENTS_COLLECTION)
.orderBy("statistics." + firebaseHelper.getCurrentUser().getUid() + ".count")
.limit(25);
If logged in user hasn't yet searched recipes with ingredients, then it should order normally. Anyway the query above is not working. Is it possible this use case to be done with Firestore.
Note: Statistics may exists or may not for logged in user, it all depends on his search.

You can't query and documents by fields that don't immediately exist within the document. Or, in other words, you can't use fields documents within subcollections that are not in the named collection being queried.
As of today (using the latest Firestore client libraries), you could instead perform a collection group query to query all of the subcollections called "statistics" for their count field. However, that will still only get you the statictics documents. You would have to iterate those documents, parse the ingredient document ID out of its reference, and individually get() each one of those documents in order to display a UI.
The collection group query would look something like this in JavaScript:
firestore
.collectionGroup("statistics")
.where(FieldPath.documentId())
.orderBy("count")
.limit(25)
You should be able to iterate those results and get the related documents with no problem.

Related

How to sort by a field in a sub-collection in firebase cloud firestore in flutter

I am trying to query a cloud firestore database and i need it to return all the documents in the chats collection sorted by the timestamp field which is a field that all the documents in the messages sub-collection have.
i tried writing a query like this.
FirebaseFirestore.instance.collection("chats").orderBy("messages.timestamp", descending: true)].get(),
but it does not return any documents when actually there are some documents there.
Firestore can only order or filter on data in the documents that it returns. There is no ability to order or filter on data outside of those documents.
So if we want to order chats in the timestamp of the last message in that chat (a common use-case), you'll have to include a lastMessageTimestamp field in the chat document itself, and update that whenever a message is written in its messages subcollection. With that lastMessageTimestamp field in place in each chats document, you can then order and filter on that.
Create a new collection called messages and store all messages for every user there (with a user id field). Reference the message uid's via an array in each chat. This way you can easily query for the messages associated with a chat session then sort them.

How can I search a specific field of a specific document in firestore using Algolia ? (Flutter)

In My database, I have a collection named 'Friends'. Inside this collection, each document represents a user. and let's say for user1, I have a field named 'friends' which is an array that contains userIDs of the friends that user1 has. In this form:
enter image description here
I followed this way instead of creating a sub-collection and represent each user by a document because I think this is more efficient in terms of documents reads when retrieving friends.
I am fine displaying friends of each user, but my problem is with implementing the Algolia search.
I have used Algolia search for searching all users but 'User' collection is different because each user is represented by a document on its own.
Thus the main question is what should I do in index.js or in the flutter code to enable full-text search using Algolia so that each user can search his list of friends for a specific name ?
Thanks.
instead of creating documents with firestore id , use name or any other known data of the user as document id so that u can easily access that document

mongodb schematic theory for feed

I'm using a mongo database for a bunch of users, inside the collection i have the userid, then i have a nested collection (Array) of the things that the user has liked, or should show up in their feed etc. My idea is that when something they like changes their feed updates (i'll remove the past entry from days ago, and reinsert a new entry for today).
OK, here's the question/problem. This concept works well when one user likes something and then later a content element they liked gets updated... BUT, what happens if I have 5 million users that all like one content element (Say, an article) and then the element is updated... How, using mongo do I insert/delete new records from 5million records all at once... perhaps someone can suggest a better schematic...
in this particular case - I will suggest a separate collection for that purpose
col events/likes{
_id,
userId,
action //add fields needed
}
then if user id:1 is a subscribed to events from user id:2, we need to retrive documents from events/likes collection when user id:2
Makes this sense in your case?

Schema on mongodb for reducing API calls with two collections

Not quite sure what the best practice is if I have two collections, a user collection and a picture collection - I do not want to embed all my pictures into my user collection.
My client searches for pictures under a certain criteria. Let's say he gets 50 pictures back from the search (i.e. one single mongodb query). Each picture is associated to one user. I want the user name displayed as well. I assume there is no way to do a single search performance wise on the user collection returning the names of each user for each picture, i.e. I would have to do 50 searches. Which means, I could only avoid this extra performance load by duplicating data (next to the user_id, also the user_name) in my pictures collection?
Same question the other way around. If my client searches for users and say 50 users are returned from the search through one single query. If I want the last associated picture + title also displayed next to the user data, I would again have to add that to the users collection, otherwise I assume I need to do 50 queries to return the picture data?
Lets say the schema for your picture collection is as such:
Picture Document
{
_id: Objectid(123),
url: 'img1.jpg',
title: 'img_one',
userId: Objectid(342)
}
1) Your picture query will return documents that look like the above. You don't have to make 50 calls to get the user associated with the images. You can simply make 1 other query to the Users Collection using the user ids taken from the picture documents like such:
db.users.find({_id: {$in[userid_1,user_id2,userid_3,...,userid_n]}})
You will receive an array of user documents with the user information. You'll have to handle their display on the client afterwards. At most you'll need 2 calls.
Alternatively
You could design the schema as such:
Picture Document
{
_id: Objectid(123),
url: 'img1.jpg',
title: 'img_one',
userId: Objectid(342),
user_name:"user associated"
}
If you design it this way. You would only require 1 call, but the username won't be in sync with user collection documents. For example lets say a user changes their name. A picture that was saved before may have the old user name.
2) You could design your User Collection as such:
User Document
{
_id: Objectid(342),
name: "Steve jobs",
last_assoc_img: {
img_id: Object(342)
url: 'img_one',
title: 'last image title
}
}
You could use the same principles as mentioned above.
Assuming that you have a user id associated with every user and you're also storing that id in the picture document, then your user <=> picture is a loosely coupled relationship.
In order to not have to make 50 separate calls, you can use the $in operator given that you are able to pull out those ids and put them into a list to run the second query. Your query will basically be in English: "Look at the collection, if it's in the list of ids, give it back to me."
If you intend on doing this a lot and intend for it to scale, I'd either recommend using a relational database or a NoSQL database that can handle joins to not force you into an embedded document schema.

Mongoid: retrieving documents whose _id exists in another collection

I am trying to fetch the documents from a collection based on the existence of a reference to these documents in another collection.
Let's say I have two collections Users and Courses and the models look like this:
User: {_id, name}
Course: {_id, name, user_id}
Note: this just a hypothetical example and not actual use case. So let's assume that duplicates are fine in the name field of Course. Let's thin Course as CourseRegistrations.
Here, I am maintaining a reference to User in the Course with the user_id holding the _Id of User. And note that its stored as a string.
Now I want to retrieve all users who are registered to a particular set of courses.
I know that it can be done with two queries. That is first run a query and get the users_id field from the Course collection for the set of courses. Then query the User collection by using $in and the user ids retrieved in the previous query. But this may not be good if the number of documents are in tens of thousands or more.
Is there a better way to do this in just one query?
What you are saying is a typical sql join. But thats not possible in mongodb. As you suggested already you can do that in 2 different queries.
There is one more way to handle it. Its not exactly a solution, but the valid workaround in NonSql databases. That is to store most frequently accessed fields inside the same collection.
You can store the some of the user collection fields, inside the course collection as embedded field.
Course : {
_id : 'xx',
name: 'yy'
user:{
fname : 'r',
lname :'v',
pic: 's'
}
}
This is a good approach if the subset of fields you intend to retrieve from user collection is less. You might be wondering the redundant user data stored in course collection, but that's exactly what makes mongodb powerful. Its a one time insert but your queries will be lot faster.