- 现在有这样的数据结构,比如在集合 class 里有一条
{
_id:ObjectId(123456789...),
number:10,
students:[
{
studentId:ObjectId(123456789...)/* 这个是student集合的id */
},
{
studentId:ObjectId(123456789...)/* 这个是student集合的id */
},
...
],
teacher:ObjectId(123456789...),
}
{
_id:ObjectId(123456789...);
name:'zhangsan',
age:20,
}
- 现在的需求是查询class的时候把student也取出来,这样就要关联查询,我用的是pipeline的$lookup,但是好像只能查询class下一级的属性,比如关联查询teacher
db.class.aggregate([
{
$lookup:
{
from: "teacher",
localField: "teacher",
foreignField: "_id",
as: "teacher"
}
}
])
- 但是student下的studentId,就无法实现,我试过
db.class.aggregate([
{
$unwind:students,
},
{
$lookup:
{
from: "student",
localField: "students.studentId",
foreignField: "_id",
as: "student",/* 这里可能不对,但是不影响把student取出来 */
}
}
])
使用MongoDB的第一件事情就是忘掉关系模型,充分利用反范式、冗余来达成最高的读写效率。你已经发现了现在的数据模型不好用,为什么不换个思路来解决问题?
决定数据模型的是你需要怎么使用这些数据。在不知道你打算怎么用这些数据的前提下,以下是一些按照常理的推测。
现在涉及的实体有3个:
其中:
对于1:n的情况,最常见的做法是把1冗余到n。比如学生可以是:
当然你也可以不要class的详细信息,毕竟一个班的学生只用查一次班级信息。
用的时候是不是会方便一些?
没错,冗余有可能会造成数据不一致,但是你真的会这么在乎一致性吗?通常的回答是不会。
比如如果班级信息如果要修改怎么办?那就会造成每个学生的班级信息都更新一遍,修改时压力会比较大操作比较复杂。但是别忘了你的系统大部分压力是来自读而不是写。班级修改的概率有多大?可能几个月不见得有一次。但是读班级的概率有多大?可能每天就有好多次。比较一下孰轻孰重不言而喻。
综上,使用MongoDB时不要用范式来约束自己,从性能,易用性来考虑就可以了。