更好的 mongodb 嵌套信息数据模型
Better mongodb data model for nested information
我正在为 mango db 设计一些数据模型,我有一些类似于下面的要求 json。
Single_Collection.
{
"collegeid": 1234,
"Name": "aaaa",
"otherinfo": 1,
"studnet":[
{
"stdid": 1,
"name": "n1"
},
{
"stdid": 2,
"name": "n2"
}
]
}
两个Collections.
大学信息
{
"collegeid": 1234,
"Name": "aaaa",
"otherinfo": 1
}
学生信息collection
{
"collegeid": 1234,
"stdid": 1,
"name": "n1"
}
{
"collegeid": 1234,
"stdid": 2,
"name": "n2"
}
就阅读表现而言,哪种方法更好(单读 collection 或将其分开),我读得更多,比如给定学生 ID 找出大学 ID。
学生证名单会很大。
我也执行更多的学生插入操作
IMO,每个模型设计都有自己的优点和缺点,我们所说的"better way"取决于您的用例(您如何查询数据?开头需要全部数据吗?需要分页吗?等...)
让我们从您的要求开始。
您的要求
- 给定一个学院ID,找出该学院的学生。
- 给定学生证,找出他的大学证。
objects
之间的关系
很明显college & student是1:m映射,因为一所学院的学生很多,但每个学生只能在一所学院呆
我将向您展示一些不同的模型设计,并提供每个模型的优缺点。
方法 1 - 让学生融入大学
这是您提到的单个设计collection。
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1,
"studnet":[
{
"stdid":1,
"name":"n1"
},
{
"stdid":2,
"name":"n2"
}
]
}
优点:
- 人类阅读和 front-end 显示的非常自然的模型。
- 在加载大学和其中的所有学生时表现良好。因为存储在引擎中的数据是连续的。引擎需要更少的 I/O 来做到这一点。
缺点:
- 如果一所大学的学生人数众多,文档的大小将会非常大。如果你经常add/remove/update学生,效率会很低。
- 没有快速实现要求 (2) 的方法。因为我们只维护college -> students 的映射,所以你必须遍历所有文档才能找出哪个college 包含指定的studentID。
方法 2 - 学生参考大学
这就是你提到的设计二Collections。它类似于 RDBMS 表,学生模型拥有其大学的参考关键点。
- 大学collection:
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1
}
- 学生collection:
{
"collegeid":1234,
"stdid":1,
"name":"n1"
}
{
"collegeid":1234,
"stdid":2,
"name":"n2"
}
优点:
- 可以达到要求(1)和(2)。请记住在
"collegeid"
和 "stdid"
字段上添加索引。
- 每个文档都可以保持在较小的体积,便于引擎存储数据。
缺点:
- 学院和学生是分开的。如果加载大学及其所有学生(需要两个查询),它将比方法 1 慢。
- UI.
显示前需要自行合并学院和学生
方法 3 - 大学和学生中的重复数据
这种方法看起来像是我们混合了方法 1 和方法 2。我们有两个 collections: college 将其学生嵌入自身,还有一个分离的学生 collection。因此,学生数据在 collection 中都是重复的。
- 大学collection:
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1,
"studnet":[ // duplicated here!
{
"stdid":1,
"name":"n1"
},
{
"stdid":2,
"name":"n2"
}
]
}
- 学生collection:
{
"collegeid":1234,
"stdid":1,
"name":"n1"
}
{
"collegeid":1234,
"stdid":2,
"name":"n2"
}
优点:
- 您拥有方法 1 和方法 2 的所有优点。
缺点:
- 大学里的文件collection会长的很大
- 大学collection和学生collection同步的数据需要自己保管。
方法 4 - 大学(仅学生 ID)和学生中的重复数据
这是方法 3 的变体。
我们假设您的用例是:
- 用户可以搜索大学。
- 用户在搜索结果中点击了一所大学。
- 新的 UI 向用户显示所有学生 ID(可能在网格或列表中)。
- 用户点击一个学号。
- 系统加载指定学生的完整数据并在另一个UI.
中显示给用户
简而言之,用户一开始不需要所有学生的完整数据,他只需要学生的基本信息(例如学号)。如果用户接受这样的场景,你可以有以下模型:
- 大学collection:
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1,
"studnetIds":[1, 2] // only student IDs are duplicated
}
- 学生collection:
{
"collegeid":1234,
"stdid":1,
"name":"n1"
}
{
"collegeid":1234,
"stdid":2,
"name":"n2"
}
学院只有学生网ID。这是与方法 3 相比的区别。
优点:
- 可以达到要求(1)和(2)。
- 您无需担心大学文件变得庞大。因为它只拥有学生证。
- 如果用户接受上述情况,这将是一个更好的设计,平衡 performance/complex/data 大小。
缺点:
- 适合特定的用例,如果以后需求变化,会破坏场景,这个模型不好。
总结
- 你应该很清楚你的用例。
- 根据用例,比较方法,看看您是否可以接受优缺点。
- 负载测试很重要!
我正在为 mango db 设计一些数据模型,我有一些类似于下面的要求 json。
Single_Collection.
{
"collegeid": 1234,
"Name": "aaaa",
"otherinfo": 1,
"studnet":[
{
"stdid": 1,
"name": "n1"
},
{
"stdid": 2,
"name": "n2"
}
]
}
两个Collections.
大学信息
{ "collegeid": 1234, "Name": "aaaa", "otherinfo": 1 }
学生信息collection
{
"collegeid": 1234,
"stdid": 1,
"name": "n1"
}
{
"collegeid": 1234,
"stdid": 2,
"name": "n2"
}
就阅读表现而言,哪种方法更好(单读 collection 或将其分开),我读得更多,比如给定学生 ID 找出大学 ID。 学生证名单会很大。
我也执行更多的学生插入操作
IMO,每个模型设计都有自己的优点和缺点,我们所说的"better way"取决于您的用例(您如何查询数据?开头需要全部数据吗?需要分页吗?等...)
让我们从您的要求开始。
您的要求
- 给定一个学院ID,找出该学院的学生。
- 给定学生证,找出他的大学证。
objects
之间的关系很明显college & student是1:m映射,因为一所学院的学生很多,但每个学生只能在一所学院呆
我将向您展示一些不同的模型设计,并提供每个模型的优缺点。
方法 1 - 让学生融入大学
这是您提到的单个设计collection。
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1,
"studnet":[
{
"stdid":1,
"name":"n1"
},
{
"stdid":2,
"name":"n2"
}
]
}
优点:
- 人类阅读和 front-end 显示的非常自然的模型。
- 在加载大学和其中的所有学生时表现良好。因为存储在引擎中的数据是连续的。引擎需要更少的 I/O 来做到这一点。
缺点:
- 如果一所大学的学生人数众多,文档的大小将会非常大。如果你经常add/remove/update学生,效率会很低。
- 没有快速实现要求 (2) 的方法。因为我们只维护college -> students 的映射,所以你必须遍历所有文档才能找出哪个college 包含指定的studentID。
方法 2 - 学生参考大学
这就是你提到的设计二Collections。它类似于 RDBMS 表,学生模型拥有其大学的参考关键点。
- 大学collection:
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1
}
- 学生collection:
{
"collegeid":1234,
"stdid":1,
"name":"n1"
}
{
"collegeid":1234,
"stdid":2,
"name":"n2"
}
优点:
- 可以达到要求(1)和(2)。请记住在
"collegeid"
和"stdid"
字段上添加索引。 - 每个文档都可以保持在较小的体积,便于引擎存储数据。
缺点:
- 学院和学生是分开的。如果加载大学及其所有学生(需要两个查询),它将比方法 1 慢。
- UI. 显示前需要自行合并学院和学生
方法 3 - 大学和学生中的重复数据
这种方法看起来像是我们混合了方法 1 和方法 2。我们有两个 collections: college 将其学生嵌入自身,还有一个分离的学生 collection。因此,学生数据在 collection 中都是重复的。
- 大学collection:
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1,
"studnet":[ // duplicated here!
{
"stdid":1,
"name":"n1"
},
{
"stdid":2,
"name":"n2"
}
]
}
- 学生collection:
{
"collegeid":1234,
"stdid":1,
"name":"n1"
}
{
"collegeid":1234,
"stdid":2,
"name":"n2"
}
优点:
- 您拥有方法 1 和方法 2 的所有优点。
缺点:
- 大学里的文件collection会长的很大
- 大学collection和学生collection同步的数据需要自己保管。
方法 4 - 大学(仅学生 ID)和学生中的重复数据
这是方法 3 的变体。 我们假设您的用例是:
- 用户可以搜索大学。
- 用户在搜索结果中点击了一所大学。
- 新的 UI 向用户显示所有学生 ID(可能在网格或列表中)。
- 用户点击一个学号。
- 系统加载指定学生的完整数据并在另一个UI. 中显示给用户
简而言之,用户一开始不需要所有学生的完整数据,他只需要学生的基本信息(例如学号)。如果用户接受这样的场景,你可以有以下模型:
- 大学collection:
{
"collegeid":1234,
"Name":"aaaa",
"otherinfo":1,
"studnetIds":[1, 2] // only student IDs are duplicated
}
- 学生collection:
{
"collegeid":1234,
"stdid":1,
"name":"n1"
}
{
"collegeid":1234,
"stdid":2,
"name":"n2"
}
学院只有学生网ID。这是与方法 3 相比的区别。
优点:
- 可以达到要求(1)和(2)。
- 您无需担心大学文件变得庞大。因为它只拥有学生证。
- 如果用户接受上述情况,这将是一个更好的设计,平衡 performance/complex/data 大小。
缺点:
- 适合特定的用例,如果以后需求变化,会破坏场景,这个模型不好。
总结
- 你应该很清楚你的用例。
- 根据用例,比较方法,看看您是否可以接受优缺点。
- 负载测试很重要!