MongoDB $lookup 遇到子文档是数组

3,231 阅读1分钟
$lookup 

  主要功能 是将每个输入待处理的文档,经过$lookup 阶段的处理,输出的新文档中会包含一个新生成的数组列(户名可根据需要命名新key的名字 )。数组列存放的数据 是 来自 被Join 集合的适配文档,如果没有,集合为空(即 为[ ])


基本语法

{ 
    $lookup: 
    { 
        from: <collection to join>, 
        localField: <field from the input documents>, 
        foreignField: <field from the documents of the "from" collection>, 
        as: <output array field> 
    } 
}

语法的解释说明

语法值解释说明
from
同一个数据库下等待被Join的集合。
localField

源集合中的match值,如果输入的集合中,某文档没有 localField

这个Key(Field),在处理的过程中,会默认为此文档含

有 localField:null的键值对。

foreignField
待Join的集合的match值,如果待Join的集合中,文档没有foreignField
值,在处理的过程中,会默认为此文档含有 foreignField:null的键值对。
as
为输出文档的新增值命名。如果输入的集合中已存在该值,则会覆盖掉,


上案例 (案例来自于群里一个小伙伴的需求)

  有两个表,分别是comment(评论表) 和 user(表)

comment

{
    "_id" : ObjectId("5ec5e48b7f7fa92fe266d246"),
    "content" : "测试",
    "reply" : [ 
        {
            "content" : "回复1",
            "userId" : ObjectId("5ec5e4c37f7fa92fe266d27e")
        }, 
        {
            "content" : "回复2",
            "userId" : ObjectId("5ec5e4ca7f7fa92fe266d285")
        }, 
        {
            "content" : "回复3",
            "userId" : ObjectId("5ec5e4dd7f7fa92fe266d290")
        }
    ]
}

user

/* 1 */
{
    "_id" : ObjectId("5ec5e4c37f7fa92fe266d27e"),
    "name" : "u1"
}

/* 2 */
{
    "_id" : ObjectId("5ec5e4ca7f7fa92fe266d285"),
    "name" : "u2"
}

/* 3 */
{
    "_id" : ObjectId("5ec5e4dd7f7fa92fe266d290"),
    "name" : "u3"
}


目标: 需要在comment 表中 关联到user,并输出用户的名称 

效果

{
    "_id" : ObjectId("5ec5e48b7f7fa92fe266d246"),
    "content" : "测试",
    "reply" : [ 
        {
            "content" : "回复1",
            "userId" : ObjectId("5ec5e4c37f7fa92fe266d27e"),
            "user" : "u1"
        }, 
        {
            "content" : "回复2",
            "userId" : ObjectId("5ec5e4ca7f7fa92fe266d285"),
            "user" : "u2"
        }, 
        {
            "content" : "回复3",
            "userId" : ObjectId("5ec5e4dd7f7fa92fe266d290"),
            "user" : "u3"
        }
    ]
}


实现语句

db.comment.aggregate([
{
    $unwind: '$reply'   // 首先拆分了reply这个数组
},
{
    $lookup: {
      from: 'user',                 // 从哪个Schema中查询
      localField: 'reply.userId',   // 本地关联的字段
      foreignField: '_id',          // user中用的关联字段
      as: 'userInfo'                // 查询到所有user后放入的字段名,这个是自定义的,是个数组类型。
    }
},
{
    $unwind:'$userInfo'    //因为lookup 关联到的数据会返回的是数组,所以继续拆分一下(这里看个人需要)
},
{
    // 按照_id 分组
    $group:{
        _id:'$_id',
        content:{$first:'$content'},
        reply:{
            $push:{
                'content':'$reply.content',
                'userId':'$reply.userId',
               'user':'$userInfo.name'
                  }
              }
          }
 }
])


这样就可实现需要的效果,MongoDB的聚合查询 是能够实现很多效果的。以上效果只是平常会经常用到的。