MongoDB中如何让$lookup实现findOne效果仅返回首个匹配结果
解决方案
实现思路
MongoDB 3.6及以上版本支持带自定义管道的$lookup语法,可以在关联collectionB的子查询阶段直接添加$limit:1限制,查询到第一条匹配结果就直接终止,不需要扫描全量匹配数据,也不需要事后对返回数组做裁剪,完全符合查询阶段优化的需求。
优化后的聚合语句
db.collectionA.aggregate([ { "$lookup": { "from": "collectionB", "let": { "a_id": "$_id" }, "pipeline": [ { "$match": { "$expr": { "$eq": [ "$_fid", "$$a_id" ] } } }, { "$limit": 1 } // 匹配到第一条就停止查询 ], "as": "matches" } }, // 可选步骤:如果要把matches从单元素数组转成普通对象,可添加以下配置 { "$addFields": { "matches": { "$first": "$matches" } } } ])
逻辑说明
- 用
let定义要从collectionA传递到子管道的变量,这里是把A表的_id存为a_id供子查询使用 - 子管道的
$match用$expr来引用let定义的变量,完成关联条件匹配 - 子管道末尾加
$limit:1,匹配到第一条符合条件的B集合文档就直接返回,不会继续扫描剩余匹配数据,大幅提升多匹配场景下的性能 - 可选的
$addFields步骤可以直接把matches字段从单元素数组转成普通对象,省去后续取数组第0位的操作
返回结果示例
[ { "_id": 1, "item": "almonds", "matches": { "_fid": 1, "_id": ObjectId("5a934e000102030405000002"), "date": "2021-01-10" } }, { "_id": 2, "item": "pecans", "matches": { "_fid": 2, "_id": ObjectId("5a934e000102030405000005"), "date": "2021-01-03" } } ]
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

