如何在 mongodb 中使用 $lookup 加入多个集合
Posted
技术标签:
【中文标题】如何在 mongodb 中使用 $lookup 加入多个集合【英文标题】:How to join multiple collections with $lookup in mongodb 【发布时间】: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"
【问题讨论】:
Multiple join conditions using the $lookup operator的可能重复 How do I query referenced objects in MongoDB?的可能重复 【参考方案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 和子对象引用 嗨,阿米特,它看起来不错,但它没有解决我的问题,这里是链接,请回复:***.com/questions/61188497/… 在您的查询中对两个连接表尝试 $unwind。 @azEnItH 嘿,阿米特,也许你可以回答你漂亮的回答的后续问题? -> ***.com/questions/67138310/…【参考方案4】:根据documentation,$lookup 只能加入一个外部集合。
您可以做的是将userInfo
和userRole
组合在一个集合中,因为提供的示例基于关系数据库模式。 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,您的代码看起来不错,但没有解决我的问题我提供了我的问题链接,请帮助我:***.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以上是关于如何在 mongodb 中使用 $lookup 加入多个集合的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Node.js 中高效/快速地执行数组连接,类似于 MongoDB $lookup?
如何使用 MongoDB 聚合 `$lookup` 作为 `findOne()`
如何在 mongodb 中使用 $lookup 从该表中获取与另一个表连接的数据