news 2026/7/8 1:57:22

MongoDB-集合(表)关联查询

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MongoDB-集合(表)关联查询

MongoDB 可以做集合(表)关联,但和 MySQL JOIN 完全不一样

一、核心结论

  1. MongoDB支持跨集合关联查询,靠聚合管道$lookup实现,等价 SQL左外连接 LEFT JOINMongoDB。
  2. 限制:只能同库关联,不支持跨库;关联结果永远是数组,没有直接 INNER JOIN,需要手动$unwind模拟内连接。
  3. 设计理念:MongoDB 优先推荐内嵌文档,少用$lookup,多表关联性能远不如 MySQL。

二、$lookup 两种用法完整示例

前置测试数据

集合 1:users用户

db.users.insertMany([ {_id: ObjectId("600001"), name:"张三", phone:"13800011111"}, {_id: ObjectId("600002"), name:"李四", phone:"13800022222"} ])

集合 2:orders订单(存 userId 关联用户)

db.orders.insertMany([ {_id:1001, userId:ObjectId("600001"), amount:99, createTime:ISODate()}, {_id:1002, userId:ObjectId("600001"), amount:199, createTime:ISODate()}, {_id:1003, userId:ObjectId("600003"), amount:59, createTime:ISODate()} ])

1)基础等值 $lookup(简单左连接)

语法

{ $lookup:{ from: "关联集合名", localField: "当前集合关联字段", foreignField: "关联集合匹配字段", as: "存放匹配结果的数组字段名" } }

查询:查订单,带出对应用户信息

db.orders.aggregate([ // 先过滤订单(可选,提前缩小数据量提升性能) {$match: {amount: {$gte: 50}}}, // 关联用户表 { $lookup:{ from:"users", localField:"userId", foreignField:"_id", as:"userList" // 匹配到的用户会存在数组里,无匹配则为空数组 [] } } ])

返回结果结构:

{ "_id":1001, "userId":ObjectId("600001"), "amount":99, "userList":[{_id:ObjectId("600001"), name:"张三", phone:"13800011111"}] }, { "_id":1003, "userId":ObjectId("600003"), "amount":59, "userList":[] // 无匹配用户,数组空 }

模拟 INNER JOIN(只保留有匹配的数据)

$unwind拆解数组,空数组会直接过滤掉:

db.orders.aggregate([ {$lookup:{from:"users",localField:"userId",foreignField:"_id",as:"userList"}}, {$unwind:"$userList"}, // 拆解数组,空数组文档直接丢弃 {$project:{ // 自定义返回字段 orderId:"$_id", amount:1, userName:"$userList.name", userPhone:"$userList.phone" }} ])

2)高级带管道 $lookup(复杂条件关联,3.6 + 支持)

基础$lookup只能等值匹配;带pipeline可以做不等值、多条件、过滤、投影。 场景:关联用户时只返回姓名,并且过滤手机号不为空的用户

db.orders.aggregate([ { $lookup:{ from:"users", let:{uid:"$userId"}, // 定义变量,当前文档字段 pipeline:[ {$match:{ $expr:{ $and:[ {$eq:["$_id","$$uid"]}, // 关联匹配 {$ne:["$phone",null]} // 附加过滤条件 ] } }}, {$project:{name:1,_id:0}} // 只返回name字段 ], as:"userInfo" } } ])

三、多集合连续关联(三表联查)

订单 → 用户 → 商品

db.orders.aggregate([ // 关联用户 {$lookup:{from:"users",localField:"userId",foreignField:"_id",as:"user"}}, {$unwind:"$user"}, // 再关联商品 {$lookup:{from:"goods",localField:"goodsId",foreignField:"_id",as:"goods"}}, {$unwind:"$goods"} ])

四、$lookup 和 MySQL JOIN 关键区别

对比项MySQL JOINMongoDB $lookup
连接类型INNER/LEFT/RIGHT/FULL仅原生左外连接,INNER 需手动 $unwind
返回结构行扁平化匹配数据封装成数组,需 $unwind 摊平
关联条件等值、不等值、多条件直接写基础版仅等值;复杂条件必须 pipeline
跨库支持不支持,只能同数据库集合关联
性能JOIN 有优化器、索引友好大量 $lookup 性能差,分片环境开销更高
外键约束支持物理外键无外键,关联靠业务 ID 手动维护

五、MongoDB 两种关联模型(最佳实践)

方案 1:内嵌文档(优先推荐,完全不用 $lookup)

适合一对一、少量关联数据,查询一次拿到全部信息,无联表开销

// 订单直接内嵌用户简化信息 { _id:1001, amount:99, user:{name:"张三", phone:"13800011111"} }

方案 2:引用 + $lookup(适合一对多、数据量大)

用户独立集合,订单存 userId,查询时用$lookup关联; 缺点:聚合查询变慢,分页、过滤逻辑复杂。

六、使用踩坑与性能优化

  1. 关联字段必须建索引foreignField(如 users._id 自带索引,自定义字段要手动创建)
  2. $match$lookup:提前过滤数据,减少关联扫描行数
  3. 大集合避免多层连续$lookup,会严重拖慢查询
  4. 一对一场景用$unwind摊平数组,简化返回结构
  5. 不要用$lookup做高频分页查询,优先内嵌设计

七、一句话总结

MongoDB 通过聚合$lookup实现集合关联,等价左连接,但性能弱于 MySQL JOIN;业务设计优先内嵌文档减少联表,实在需要拆分集合再使用引用 +$lookup

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 1:56:31

音视频编解码:VP8 / VP9 / H.264 / Opus

音视频编解码:VP8 / VP9 / H.264 / Opus WebRTC 支持哪些音视频编解码器?各有什么优缺点?怎么选?码率怎么设?这篇讲 WebRTC 常用的视频编码(VP8/VP9/H.264/AV1)和音频编码(Opus/G.71…

作者头像 李华
网站建设 2026/7/8 1:55:16

3分钟搞定网易云插件安装:BetterNCM-Installer终极解决方案

3分钟搞定网易云插件安装:BetterNCM-Installer终极解决方案 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 还在为网易云音乐功能单一而烦恼吗?每次手动安装插件…

作者头像 李华
网站建设 2026/7/8 1:54:47

spring通过方法注入,针对多实例的Bean

方法使用Lookup方式 1、目标bean类 Service Scope("prototype") public class ClientService {PostConstructvoid init(){System.out.println("初始化示例");}public String doSomething() {return "测试客户端代码";} }2、新建抽象类LookClient…

作者头像 李华
网站建设 2026/7/8 1:53:44

2026年7月探寻四川信誉优良的GEO优化运营商

在生成式人工智能技术快速渗透各行各业的当下,企业数字化进程正从“信息上网”迈入“认知构建”的新阶段。大模型和AI搜索的普及,让市场关注点从传统的网页排名转向了生成式答案中的企业可见度与信息可信度。对于区域产业而言,本土科技服务商…

作者头像 李华