【问题标题】:How to join multiple collections with $lookup in mongodb如何在 mongodb 中使用 $lookup 加入多个集合
【发布时间】:2016-06-19 05:44:23
【问题描述】:

我想使用聚合 $lookup 在 MongoDB 中加入两个以上的集合。是否可以加入?举几个例子吧。

这里有三个集合:

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"
}

【问题讨论】:

标签: mongodb join mongodb-query


【解决方案1】:

第一次查找找到 p.cid = categories._id 的所有产品,同样是第二次查找 查找 p.sid = subcategories._id 的所有产品。

让 dataQuery :any = await ProductModel.aggregate([ { $lookup:{ 来自:“类别”, 本地字段:“cid”, 外国字段:“_id”, 作为:“产品” } }, { $unwind: "$products" }, { $查找:{ 来自:“子类别”, 本地字段:“sid”, 外国字段:“_id”, 如:“产品列表” } }, { $unwind: "$productList" }, { $项目:{ 产品列表:0 } }

  ]);

【讨论】:

    【解决方案2】:

    首先添加集合,然后对这些集合应用查找。不要使用$unwind as 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"
            }
        ] }
    

    谢谢。

    【讨论】:

    • 如果一个集合中有多个文档,那么所有文档都将显示在数组中。
    • 非常感谢您的回答。这个回答帮助我理解了聚合。你刚刚拯救了我的一天
    【解决方案3】:

    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 意味着删除 "{ $unwind:"$user_role" }" 来自从 user_role 中获取数组中数据的查询
    • 这对我很有帮助;特别是在投影中使用 $unwind 和子对象引用
    • 嗨,阿米特,它看起来不错,但它没有解决我的问题,这里是链接,请回复:stackoverflow.com/questions/61188497/…
    • 在您的查询中对两个连接表尝试 $unwind。 @azEnItH
    • 嘿,阿米特,也许你可以回答你漂亮的回答的后续问题? -> stackoverflow.com/questions/67138310/…
    【解决方案4】:

    根据documentation,$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?我在文档链接中没有发现任何限制。谢谢
    【解决方案5】:

    您实际上可以链接多个 $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 并不是关系型的,但它很有用。

    【讨论】:

    • 如果我们想将 userinfo 显示为用户角色中的一个数组怎么办?如何做到这一点
    • 并不是一个关系数据库,但每个文档都有 16MB 的上限,这迫使您将无限数组分散到进一步的集合中...catch 22
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 2023-03-09
    • 2021-11-04
    • 2022-01-01
    相关资源
    最近更新 更多