Firebase 有效地模拟 nXn 关系
Firebase efficiently model nXn relationship
假设我有以下场景:
我有多个活动,多个用户可以参加。此外,用户可以参加多个活动。存储所需信息并保持数据一致性的最佳方式是什么?
这是我的想法以及我不太喜欢它们的原因:
collection "events" -> event document -> subcollection "users" -> user document
问题:
每个用户都存在于每个事件上,从而导致每个用户有多个文档。我不能只更新用户信息,因为我需要写入每个相关事件文档并获取相关用户文档。
如果试图尽可能减少 reads/writes ,那真是一场灾难
例如:
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
问题:
每个事件都存在于每个用户上,导致每个事件的多个文档。 (与第一种情况相同的问题,只是反过来)
collection "users" and collection "events"
每个都有用户和事件作为从属于它们的文档。
有一个数组 attending_events
,其中包含相关的事件 ID。
问题:
有点像 SQL 的排序方式。需要使用 forEach()
函数通过单独的查询获取每个文档。
例如
this.afs.collection('events').doc(eventId).get().then(res => {
res.users.forEach(elem => {
this.afs.collection('users').doc(elem.name).get()
//Change name accordingly
})
})
我错过了什么,是否有更好的方法来模拟所需的架构?
When using collection "events" -> event document -> subcollection "users" -> user document
并没有您想的那么糟糕。这种做法称为 denormalization 并且是 Firebase 的常见做法。如果您是 NoSQL 数据库的新手,我建议您观看此视频 Denormalization is normal with the Firebase Database 以便更好地理解。它适用于 Firebase 实时数据库,但同样的规则适用于 Cloud Firestore。
I want to be able to change user information or event information without the need of fetching hundreds of documents.
如果您认为用户详细信息会经常更改,那么您应该考虑在每个 user
对象下存储一个 array
的事件 ID,而不是 使用子集合。同样,你也应该在每个 event
对象下添加一个 array
的 UID。您的新架构应如下所示:
Firestore-root
|
--- users (collection)
| |
| --- uid (document)
| |
| --- events: ["evenIdOne", "evenIdTwo", "evenIdThere"]
| |
| --- //Other user properties
|
--- events (collection)
|
--- eventId (document)
|
--- users: ["uidOne", "euidTwo", "uidThere"]
|
--- //Other event properties
由于您只持有引用,因此当用户名更改时,无需在 events
子集合中存在的所有用户对象中更新它。但是请记住,在这种方法中,例如要获取用户分开的所有事件,您应该创建两个查询,一个是从用户文档中获取事件 ID,第二个是根据这些事件 ID 获取事件文档。
基本上这是在使用非规范化和将数据存储在数组之间的权衡。
What's the best way of storing the required information with maintaining data consistency?
通常,我们根据要执行的查询创建数据库模式。有关更多信息,我还建议从以下 post:
中查看我的答案
假设我有以下场景:
我有多个活动,多个用户可以参加。此外,用户可以参加多个活动。存储所需信息并保持数据一致性的最佳方式是什么?
这是我的想法以及我不太喜欢它们的原因:
collection "events" -> event document -> subcollection "users" -> user document
问题:
每个用户都存在于每个事件上,从而导致每个用户有多个文档。我不能只更新用户信息,因为我需要写入每个相关事件文档并获取相关用户文档。
如果试图尽可能减少 reads/writes ,那真是一场灾难
例如:
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
问题:
每个事件都存在于每个用户上,导致每个事件的多个文档。 (与第一种情况相同的问题,只是反过来)
collection "users" and collection "events"
每个都有用户和事件作为从属于它们的文档。
有一个数组 attending_events
,其中包含相关的事件 ID。
问题:
有点像 SQL 的排序方式。需要使用 forEach()
函数通过单独的查询获取每个文档。
例如
this.afs.collection('events').doc(eventId).get().then(res => {
res.users.forEach(elem => {
this.afs.collection('users').doc(elem.name).get()
//Change name accordingly
})
})
我错过了什么,是否有更好的方法来模拟所需的架构?
When using
collection "events" -> event document -> subcollection "users" -> user document
并没有您想的那么糟糕。这种做法称为 denormalization 并且是 Firebase 的常见做法。如果您是 NoSQL 数据库的新手,我建议您观看此视频 Denormalization is normal with the Firebase Database 以便更好地理解。它适用于 Firebase 实时数据库,但同样的规则适用于 Cloud Firestore。
I want to be able to change user information or event information without the need of fetching hundreds of documents.
如果您认为用户详细信息会经常更改,那么您应该考虑在每个 user
对象下存储一个 array
的事件 ID,而不是 使用子集合。同样,你也应该在每个 event
对象下添加一个 array
的 UID。您的新架构应如下所示:
Firestore-root
|
--- users (collection)
| |
| --- uid (document)
| |
| --- events: ["evenIdOne", "evenIdTwo", "evenIdThere"]
| |
| --- //Other user properties
|
--- events (collection)
|
--- eventId (document)
|
--- users: ["uidOne", "euidTwo", "uidThere"]
|
--- //Other event properties
由于您只持有引用,因此当用户名更改时,无需在 events
子集合中存在的所有用户对象中更新它。但是请记住,在这种方法中,例如要获取用户分开的所有事件,您应该创建两个查询,一个是从用户文档中获取事件 ID,第二个是根据这些事件 ID 获取事件文档。
基本上这是在使用非规范化和将数据存储在数组之间的权衡。
What's the best way of storing the required information with maintaining data consistency?
通常,我们根据要执行的查询创建数据库模式。有关更多信息,我还建议从以下 post:
中查看我的答案