MongoDB如何基于特定字段值实现$lookup关联查询
MongoDB 单次聚合实现优先级关联查询
我是MongoDB新手,现在有个需求:现有两个集合Collection1和Collection2,结构如下:
Collection1 结构
[ { "id": "1a5086e1-c9ce-4c65-a4b3-u753hd7278", "entityId": "https://sxy.co", "providedBy": "text value", "type": "Display", "exhibitCreatedDate": "2023-01-13T09:27:04.000561Z", "effectiveDate": "2020", "link_id": "1a5086e1-c9ce-4c65-a4b3-yE46734g6j891" }, { "id": "1a5086e1-c9ce-4c65-oa4b3-u753djf7278", "entityId": "https://sijh.co", "providedBy": "text value", "type": "Actual", "exhibitCreatedDate": "2023-01-13T09:27:04.000561Z", "effectiveDate": "2020", "link_id": "1a5086e1-c9ce-4c65-a4b3-yE46734g6j891" } ]
Collection2 结构
[ { "_id": "1a5086e1-c9ce-4c65-a4b3-yE46734g6j891", "telephoneNumber": "+44-20-7424-4200", "faxNumber": "+44-20-7483-2293", "createdDate": "2023-01-13T09:27:04.000255Z", "modifiedDate": "2023-01-13T09:27:04.000255Z" }, { "_id": "1a5086e1-c9ce-4c65-oa4b3-u753djf7278", "type": "test value", "telephoneNumber": "+44-20-7424-4200", "faxNumber": "+44-20-7483-2293", "createdDate": "2023-01-13T09:27:04.000255Z", "modifiedDate": "2023-01-13T09:27:04.000255Z" } ]
需求是基于link_id和_id字段执行$lookup关联,规则为:优先对Collection1中type为"Display"的文档执行关联;如果没有这类文档,再对type为"Actual"的文档执行关联。目前我用两次聚合查询实现这个逻辑,能不能合并成单次查询?
当前的两次查询代码:
// 查询Display类型文档并关联 db.Collection1.aggregate([ { $match: { type: "Display" } }, { $lookup: { from: "Collection2", localField: "link_id", foreignField: "_id", as: "Detail" } }, { $sort: { exhibitCreatedDate: -1 } } ]).pretty(); // 查询Actual类型文档并关联 db.Collection1.aggregate([ { $match: { type: "Actual" } }, { $lookup: { from: "Collection2", localField: "link_id", foreignField: "_id", as: "Detail" } }, { $sort: { exhibitCreatedDate: -1 } } ]).pretty();
解决方案:单次聚合查询实现
可以通过聚合的多阶段组合实现这个逻辑,核心思路是先按link_id分组,优先保留type为"Display"的文档,再执行关联操作。完整代码如下:
db.Collection1.aggregate([ // 筛选出符合条件的类型(Display或Actual) { $match: { $or: [ { type: "Display" }, { type: "Actual" } ] } }, // 给文档设置优先级,Display优先级高于Actual { $addFields: { priority: { $cond: { if: { $eq: ["$type", "Display"] }, then: 1, else: 2 } } } }, // 按link_id分组,每组只保留优先级最高的文档(优先Display) { $group: { _id: "$link_id", doc: { $first: "$$ROOT" } } }, // 恢复文档的根结构 { $replaceRoot: { newRoot: "$doc" } }, // 关联Collection2集合 { $lookup: { from: "Collection2", localField: "link_id", foreignField: "_id", as: "Detail" } }, // 按创建日期倒序排序 { $sort: { exhibitCreatedDate: -1 } }, // 移除优先级字段(可选) { $project: { priority: 0 } } ]).pretty();
逻辑说明:
- $match:过滤出仅包含
Display和Actual类型的文档,减少后续处理的数据量。 - $addFields:为文档添加优先级标识,
Display设为1(更高优先级),Actual设为2。 - $group:按
link_id分组,用$first保留每组中优先级最高的文档——如果同一link_id下既有Display又有Actual,只会保留Display;如果只有Actual,则保留Actual。 - $replaceRoot:将分组后的文档恢复为根结构,方便后续关联操作。
- $lookup:执行关联查询,拉取Collection2中的对应数据。
- $sort:保持和原查询一致的倒序排序逻辑。
- $project:可选步骤,移除临时添加的优先级字段,让返回结果更整洁。
这样就能通过单次聚合查询实现你需要的优先级关联逻辑,无需分两次查询。
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

