I want to implement the following constraints:
- Users can save movies (titles) and view the title uploaded by other users too.
- All users must be able to access all of the movies, but must only be able to edit/add/delete their own.
- Users should not be able to view in any way who added a movie, only if that person is them. (I would like to make it so they can't even view if "X" and "Y" movie are from the same user)
- User can have up to 3 movies added (this number is the client's requested one, but what if they change their mind, how to make it scalable?)
I have users logging in with firebase authentication, thus getting a user uid. I would like to make most constraints/checks on firestore server side, wherever possible, using firestore rules, on whatever other technology I don't know of as of writing this question.
I have thought of the following structures:
movies: {
userUid1: {
movie1:{
name: "dummy name 1"
},
movie2:{
name: "dummy name 2"
}
},
userUid2: {
movie1:{
name: "first dummy name"
},
movie2:{
name: "second dummy name"
},
movie3:{
name: "third dummy name"
}
}
}
or:
movies: {
movieUid1: {
name: "dummy name 1",
userId: "userUid1"
},
movieUid2: {
name: "dummy name 2",
userId: "userUid1"
},
movieUid3: {
name: "dummy name 3",
userId: "userUid2"
},
movieUid4: {
name: "dummy name 4",
userId: "userUid2"
},
movieUid5: {
name: "dummy name 5",
userId: "userUid2"
}
}
This project is only for some friends, so nothing serious, but still I would like to structure the best way possible. I don't think this is relevant, but I use flutter to create the app.
CodePudding user response:
If you need to track number of movies saved by a user (or store any user related information later), you can try the following structure:
users -> { userId } -> movies -> { movieId }
(col) (doc) (col) (doc)
Any user related user information can be stored in user's document and their movies in a sub-collection.
Users can save movies (titles) and view the title uploaded by other users too.
You can then use Collection Group queries to list all movies.
All users must be able to access all of the movies, but must only be able to edit/add/delete their own.
You can use security rules for that. These rules should work:
match /users/{userId}/movies/{movieId} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the user who added movie can write/delete
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
You need to store the user's UID in movies document for the above rules to work. You can use get()
to read data from user's document.
User can have up to 3 movies added
You can add a rule that reads number of movies added by user from user's document and reject create if that value is 3.
You can checkout this answer to read more about root level collections and sub-collections:
Are there any benefits of using subcollections in firestore?
CodePudding user response:
Generally speaking, I think the typical approach would be to do both. Firestore doesn't do a great job on a query like "show me all movies in the movie collection with userID xyz" or "find me the movie record xyz that's buried under some user who I don't know".
So typically, if you need to look up a specific movie, as well as get a list of all movies for one user, you would store the data in both ways and then use triggers (in this case Firebase functions) to keep them in sync.
The answer to this post (What is denormalization in Firebase Cloud Firestore?) has a great explanation.