如何在mongodb中使用$ lookup加入多个集合


78

我想使用聚合在MongoDB中加入两个以上的集合$lookup。有可能参加吗?给我一些例子。

这里有三个集合:

users

{    
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
    "email" : "admin@gmail.com",
    "userId" : "AD",
    "userName" : "admin"
}

userinfo

{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "phone" : "0000000000"
}

userrole

{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "role" : "admin"
}


Answers:


124

Mongodb 3.2和更高版本支持的连接功能。您可以通过使用聚合查询来使用联接。
您可以使用以下示例进行操作:

db.users.aggregate([

    // Join with user_info table
    {
        $lookup:{
            from: "userinfo",       // other table name
            localField: "userId",   // name of users table field
            foreignField: "userId", // name of userinfo table field
            as: "user_info"         // alias for userinfo table
        }
    },
    {   $unwind:"$user_info" },     // $unwind used for getting data in object or for one record only

    // Join with user_role table
    {
        $lookup:{
            from: "userrole", 
            localField: "userId", 
            foreignField: "userId",
            as: "user_role"
        }
    },
    {   $unwind:"$user_role" },

    // define some conditions here 
    {
        $match:{
            $and:[{"userName" : "admin"}]
        }
    },

    // define which fields are you want to fetch
    {   
        $project:{
            _id : 1,
            email : 1,
            userName : 1,
            userPhone : "$user_info.phone",
            role : "$user_role.role",
        } 
    }
]);

这样会得到如下结果:

{
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
    "email" : "admin@gmail.com",
    "userName" : "admin",
    "userPhone" : "0000000000",
    "role" : "admin"
}

希望这对您或其他人有帮助。

谢谢


如果您要从其他表中删除数组中的数据,而不仅仅是从该表中删除$ unwind,则意味着从用于从user_role表中获取数组中数据的查询中删除“ {$ unwind:“ $ user_role”}
Amit Kumar

这对我很有帮助;特别是在投影中使用$ unwind和子对象引用
Mr.Budris '18

嗨,艾米特它看起来不错,但它并没有在这里解决我的问题是链接,请给予回应: stackoverflow.com/questions/61188497/...
天顶

在查询中为两个联接表尝试$ unwind。@azEnItH
阿米特·库玛

40

实际上,您可以链接多个$ lookup阶段。根据profesor79共享的集合名称,可以执行以下操作:

db.sivaUserInfo.aggregate([
    {
        $lookup: {
           from: "sivaUserRole",
           localField: "userId",
           foreignField: "userId",
           as: "userRole"
        }
    },
    {
        $unwind: "$userRole"
    },
    {
        $lookup: {
            from: "sivaUserInfo",
            localField: "userId",
            foreignField: "userId",
            as: "userInfo"
        }
    },
    {
        $unwind: "$userInfo"
    }
])

这将返回以下结构:

{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "phone" : "0000000000",
    "userRole" : {
        "_id" : ObjectId("56d82612b63f1c31cf906003"),
        "userId" : "AD",
        "role" : "admin"
    },
    "userInfo" : {
        "_id" : ObjectId("56d82612b63f1c31cf906003"),
        "userId" : "AD",
        "phone" : "0000000000"
    }
}

也许这可以被认为是一种反模式,因为MongoDB并不意味着是关系型的,但是它很有用。


1
如果我们想将userinfo显示为用户角色中的混蛋怎么办?如何做到这一点
Muneem Habib

14

根据文档,$ lookup只能加入一个外部集合。

你可以做的是结合userInfouserRole到一个集合中,如所提供的示例是基于关系数据库架构的。Mongo是noSQL数据库-这就需要不同的文档管理方法。

请在下面的两步查询中找到该查询,该查询将userInfo与userRole结合在一起-创建用于上一次查询的新临时集合以显示组合数据。在上一个查询中,有一个选项可以使用$ out并使用合并的数据创建新的集合以供以后使用。

创建收藏

db.sivaUser.insert(
{    
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
        "email" : "admin@gmail.com",
        "userId" : "AD",
        "userName" : "admin"
})

//"userinfo"
db.sivaUserInfo.insert(
{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "phone" : "0000000000"
})

//"userrole"
db.sivaUserRole.insert(
{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "role" : "admin"
})

“全部加入”他们:-)

db.sivaUserInfo.aggregate([
    {$lookup:
        {
           from: "sivaUserRole",
           localField: "userId",
           foreignField: "userId",
           as: "userRole"
        }
    },
    {
        $unwind:"$userRole"
    },
    {
        $project:{
            "_id":1,
            "userId" : 1,
            "phone" : 1,
            "role" :"$userRole.role"
        }
    },
    {
        $out:"sivaUserTmp"
    }
])


db.sivaUserTmp.aggregate([
    {$lookup:
        {
           from: "sivaUser",
           localField: "userId",
           foreignField: "userId",
           as: "user"
        }
    },
    {
        $unwind:"$user"
    },
    {
        $project:{
            "_id":1,
            "userId" : 1,
            "phone" : 1,
            "role" :1,
            "email" : "$user.email",
            "userName" : "$user.userName"
        }
    }
])

嗨,PROFESOR你的代码看起来不错,但并没有解决我的问题,我提供我的问题链接,请帮助我:stackoverflow.com/questions/61188497/...
天顶

有谁知道,如果这种说法仍然是正确的:$lookup can join only one external collection?我在文档链接中没有发现任何限制。谢谢
以色列佩克

1

首先添加集合,然后对这些集合应用查找。不要使用,$unwind 因为展开会简单地将每个集合的所有文档分开。因此,应用简单的查找,然后$project用于投影。这是mongoDB查询:

db.userInfo.aggregate([
    {
        $lookup: {
           from: "userRole",
           localField: "userId",
           foreignField: "userId",
           as: "userRole"
        }
    },
    {
        $lookup: {
            from: "userInfo",
            localField: "userId",
            foreignField: "userId",
            as: "userInfo"
        }
    },
    {$project: {
        "_id":0,
        "userRole._id":0,
        "userInfo._id":0
        }
        } ])

这是输出:

/* 1 */ {
    "userId" : "AD",
    "phone" : "0000000000",
    "userRole" : [ 
        {
            "userId" : "AD",
            "role" : "admin"
        }
    ],
    "userInfo" : [ 
        {
            "userId" : "AD",
            "phone" : "0000000000"
        }
    ] }

谢谢。


2
如果集合中将有多个文档,则所有文档都将与一起显示在数组中。
nixxo_raa

非常感谢您的答复。此答复帮助我了解汇总。您刚刚保存了我的一天
Bibek
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.