mongodb的关联查询$lookup

  • 现在有这样的数据结构,比如在集合 class 里有一条
    {
        _id:ObjectId(123456789...),
        number:10,
        students:[
            {
                studentId:ObjectId(123456789...)/* 这个是student集合的id */
            },
            {
                studentId:ObjectId(123456789...)/* 这个是student集合的id */
            },
            ...
        ],
        teacher:ObjectId(123456789...),
        
    }
  • student 集合的数据结构是
    {
        _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取出来 */
            }
       }
    ])
  • 希望有大佬可以解惑!不能改数据结构
阅读 4.2k
1 个回答

使用MongoDB的第一件事情就是忘掉关系模型,充分利用反范式、冗余来达成最高的读写效率。你已经发现了现在的数据模型不好用,为什么不换个思路来解决问题?
决定数据模型的是你需要怎么使用这些数据。在不知道你打算怎么用这些数据的前提下,以下是一些按照常理的推测。
现在涉及的实体有3个:

  • teacher
  • student
  • class

其中:

  • teacher:class = 1:n
  • class:student = 1:n

对于1:n的情况,最常见的做法是把1冗余到n。比如学生可以是:

{
    _id:ObjectId(123456789...),
    name:'zhangsan',
    age:20,
    class: {
        classId: ObjectId(123456789...),
        number:10,
        // 其他常用字段
    }
}

当然你也可以不要class的详细信息,毕竟一个班的学生只用查一次班级信息。

{
    _id:ObjectId(123456789...),
    name:'zhangsan',
    age:20,
    classId: ObjectId(123456789...)
}

用的时候是不是会方便一些?
没错,冗余有可能会造成数据不一致,但是你真的会这么在乎一致性吗?通常的回答是不会。
比如如果班级信息如果要修改怎么办?那就会造成每个学生的班级信息都更新一遍,修改时压力会比较大操作比较复杂。但是别忘了你的系统大部分压力是来自读而不是写。班级修改的概率有多大?可能几个月不见得有一次。但是读班级的概率有多大?可能每天就有好多次。比较一下孰轻孰重不言而喻。

综上,使用MongoDB时不要用范式来约束自己,从性能,易用性来考虑就可以了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题