MongoDB是一种非关系型数据库,它不支持SQL中的JOIN操作,也就是说,它不能直接在不同的集合(collection)之间进行关联查询。但是,MongoDB提供了一个$lookup聚合操作符,可以实现类似于JOIN的功能,即从另一个集合中获取数据并将其添加到原始集合中。
$lookup操作符有两种形式:一种是简单形式,另一种是管道形式。简单形式只能指定一个外部集合和一个本地字段与外部字段之间的等值匹配条件,而管道形式可以指定一个外部集合和一个子聚合管道,可以实现更复杂的关联查询逻辑。
例如,假设我们有两个集合:orders和inventory,分别存储订单信息和库存信息。我们想要查询所有订单中包含了库存中状态为\"A\"的商品的订单信息。我们可以使用$lookup的管道形式来实现这个需求,如下所示:
from: \"inventory\", // 指定外部集合
let: { order_item: \"$item\", order_qty: \"$ordered\" }, // 定义本地变量
pipeline: [ // 定义子聚合管道
$match: { // 过滤外部集合中符合条件的文档
$expr: { // 使用表达式比较本地变量和外部字段
{ $eq: [\"$sku\", \"$$order_item\"] }, // sku字段等于本地变量order_item
{ $gte: [\"$instock\", \"$$order_qty\"] }, // instock字段大于等于本地变量order_qty
{ $eq: [\"$status\", \"A\"] } // status字段等于\"A\"
$project: { // 投影外部集合中需要的字段
as: \"inventory_docs\" // 指定输出数组的字段名
上述代码中,我们使用了$lookup的管道形式,首先指定了外部集合为inventory,然后定义了两个本地变量order_item和order_qty,分别对应orders集合中的item字段和ordered字段。接着,我们定义了一个子聚合管道,其中包含了两个操作符:$match和$project。$match操作符用于过滤外部集合中符合条件的文档,我们使用了$expr操作符来使用表达式比较本地变量和外部字段。我们指定了三个条件:sku字段等于本地变量order_item,instock字段大于等于本地变量order_qty,以及status字段等于\"A\"。这样,我们就只保留了库存中状态为\"A\"且数量足够的商品。然后,我们使用了$project操作符来投影外部集合中需要的字段,我们只保留了sku和instock两个字段,并去掉了_id字段。最后,我们指定了输出数组的字段名为inventory_docs,并将其添加到原始集合中。
这样,我们就实现了带条件的关联查询,可以得到如下的结果:
可以看到,只有前两个订单中的商品在库存中状态为\"A\"且数量足够,因此只有它们的inventory_docs数组中有数据,而第三个订单中的商品在库存中状态为\"B\"且数量不足,因此它的inventory_docs数组为空。