问题
Let's say I have the following scenario:
I have multiple events, that multiple users can attend. Also, users can attend multiple events. What's the best way of storing the required information with maintaining data consistency?
Here's what I came up with and why I don't really fancy them:
collection "events" -> event document -> subcollection "users" -> user document
Problem:
Each user exists on each event, resulting in multiple documents of each user. I can't just update user information as I would need to write to every relevant event document and fetch the relevant user documents.
Really a disaster if trying to make the least reads/writes possible
E.g.:
this.afs.collection('events').get().then(res => {
res.forEach(document => {
document.ref.collection('users', ref => ref.where('name', '==', 'Will Smith')).get()
//Change name accordingly
})
})
collection "users" -> user document -> subcollection "events" -> event document
Problem:
Each event exists on each user, resulting in multiple documents of each event. (Same problem as in the first scenario, just the other way around)
collection "users" and collection "events"
with each having users and events as documents subordinate to them.
There's an array attending_events
which has the relevant event id's in it.
Problem:
Kind of the SQL way of sorting things. There's the need of getting each document with a seperate query using a forEach()
function.
E.g.
this.afs.collection('events').doc(eventId).get().then(res => {
res.users.forEach(elem => {
this.afs.collection('users').doc(elem.name).get()
//Change name accordingly
})
})
What am I missing, is there better approaches to model the desired architecture?
回答1:
When using
collection "events" -> event document -> subcollection "users" -> user document
It's not so bad as you might think. This practice is called denormalization and is a common practice when it comes to Firebase. If you are new to NoSQL 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 the same rules apply in the case of Cloud Firestore.
I want to be able to change user information or event information without the need of fetching hundreds of documents.
If you think that user details will be changed very often, then you should consider storing under each user
object an array
of event IDs and not use a subcollection. In the same way, you should also add under each event
object an array
of UIDs. Your new schema should look like this:
Firestore-root
|
--- users (collection)
| |
| --- uid (document)
| |
| --- events: ["evenIdOne", "evenIdTwo", "evenIdThere"]
| |
| --- //Other user properties
|
--- events (collection)
|
--- eventId (document)
|
--- users: ["uidOne", "euidTwo", "uidThere"]
|
--- //Other event properties
Since you are holding only references, when the name of a user is changed, there is no need to update it in all user objects that exist in events
subcollection. But remember that in this approach, to get for example all events a user is apart off, you should create two queries, one to get the event IDs from user document and second to get event documents based on those event IDs.
Basically it's a trade-off between using denormalization and storing data in arrays.
What's the best way of storing the required information with maintaining data consistency?
Usually, we create the database schema according to the queries we intend to perform. For more infos, I also recommend to see my answer from the following post:
- What is the correct way to structure this kind of data in Firestore?
来源:https://stackoverflow.com/questions/58818379/firebase-efficiently-model-nxn-relationship