I’m building a feed where a user can follow projects, and those projects will show up in the user’s feed, sorted by a lastUpdated
field, and allow for pagination, but I can’t figure out what the best approach is.
The basic Firestore structure looks like:
users (collection)
projects (subcollection)
lastUpdated (timestamp)
followingProjects (array of project Document IDs)
I could use an in
operator like:
let followingProjects = user.followingProjects
firestore().collectionGroup("projects")
.whereField(FieldPath.documentID(), in: followingProjects)
.order(by: "lastUpdated", descending: true)
.limit(to: 20)
// And later for pagination :
.start(afterDocument: startAfter)
But I believe the in
operator is limited to 30 values in followingProjects
, and I would like to allow following more than 30 projects.
A solution I can think of is to create a separate subcollection for followingProjects, so the new structure would be:
users (collection)
projects (subcollection)
lastUpdated (timestamp)
followingProjects (subcollection)
id (string)
lastUpdated (timestamp)
In this case, to get the feed, I’d run a collectionGroup query to get the latest followingProjects so I can sort and paginate, followed by individual getDocument()
queries for each project. Every time a project is updated, it would have to update the lastUpdated
for each user that’s following the project though, and this seems inefficient.
Is there a better approach I’m missing?
2
Answers
I found the answer I needed in another answer!
https://stackoverflow.com/a/58100387/482536
Instead of storing Project IDs in a
followingProjects
array as part of the User, the Project should store User IDs in afollowers
array. Then I can run the following query without worrying about the disjunctions limit, and there are no separate documents to keep updated whenever a Project is updated.In a collection group index, the
__name__
field (which is whatFieldPath.documentID()
maps to) is populated with the path of the document, rather than just its document ID. So if you want to filter onFieldPath.documentID()
, you will need to know the entire path of the document(s).Alternatively, you can add a regular field with the document ID to each document, and filter on that in your collection group query.