1. $lookup 的语义与跨集合 JOIN 模拟?
请解释 MongoDB 聚合管道中 $lookup 的语义,以及它是如何模拟关系型数据库中的跨集合 JOIN 的?
- $lookup 只能在聚合管道中使用,且默认是"左外连接"(left outer join)语义
- foreignField 与 localField 的匹配规则及索引利用
- 与关系型数据库 JOIN 在性能、内存与灵活性上的差异
$lookup 是聚合管道中用于执行跨集合关联的阶段,它把"from"集合(一般称为"外部集合"或"被关联集合")中与指定字段匹配的文档以数组形式合并到当前文档中。默认行为是等价于关系型数据库的左外连接:当前集合(local collection)的每个文档都会保留,即使没有匹配也会得到空数组;而被关联集合中多余的文档不会被输出。执行时,MongoDB 会对 localField 的每个值在 from 集合上进行匹配,若 from 集合的 foreignField 存在索引(通常应建在 foreignField 和 localField 上),则可以在不扫描整个集合的情况下完成关联。相比 SQL 的 JOIN,$lookup 的结果是"数组"而非"扁平行",且默认只能做等值连接,不能做不等值连接,除非使用 pipeline 语法。
$lookup 的"左外连接"语义意味着它不会丢失主表文档,这一点对理解结果集很重要。性能上,$lookup 常常成为管道瓶颈,因为每个本地文档都要在外部集合做一次匹配;因此必须为 foreignField 建索引,否则会退化为全表扫描。了解其"数组化输出"与"仅等值匹配"这两点,是判断何时该用 $lookup、何时该反规范化的关键。
// 订单集合关联用户集合,返回每个订单及其用户信息
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}
}
]);