My objective:
The web app (similar to Google Drive) has 2 screens.
First screen is 'My Story' which displays all the story documents whom I'm the owner.
Second screen is 'Shared with me' which displays all the story documents that I'm either reader, writer, or commenter.
We have this /stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time ...",
roles: {
alice: "owner",
bob: "reader",
david: "writer",
jane: "commenter"
// ...
}
}
Full data structure reference: https://firebase.google.com/docs/firestore/solutions/role-based-access
Question: How to write the below query to fulfil the above objective?
db
.collection('stories')
.where(`roles.${uid}`, '==', 'owner')
The above query does NOT work because it will require Firestore to index roles.alice, roles.bob, roles.david, roles.jane, and roles.[all_uid].
Edit #1: Found a related post (with no answers) asking about Firestore querying with roles
You cannot achieve this with your actual database structure in a way that you don't need to create an index for each user separately. To sovle this, you should duplicate your data. This practice is called denormalization
and is a common practice when it comes to Firebase. If you are new to NoQSL databases, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding. It is for Firebase realtime database but same rules apply to Cloud Firestore.
Also, 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.
That being said, you should create another collection named userStories
, where you should add as documents all stories where a user is owner
. So you database structure should look similar to this:
Firestore-root
|
--- userStories (collection)
|
--- uid (document)
|
--- allStories (collection)
|
--- storyId
|
--- role: "owner"
So a query like this:
db.collection('userStories').doc(${uid})
.collection('allStories').where(`role`, '==', 'owner');
Will work perfectly fine.