MongoDB:如何关联两集合获取指定条件文档($unionWith使用问题)
MongoDB跨集合聚合:筛选未完成最新测试的测试人员
我有两个集合BulkTests和Testers,需求是:
- 获取
BulkTests集合中testId的最大值 - 找出
Testers集合中testResponses字段的最大值(即lastTest)不等于该最大值的文档
尝试用$unionWith实现但没成功,当前聚合管道能正确获取lastTest,但match阶段的最大值是硬编码的,需要替换为BulkTests的最大testId。
集合结构
BulkTests
[ { "_id": "65b82f4b13f7b6653662795d", "testDateTime": "2024-01-29T23:05:47.940+00:00", "testId": 19 }, { "_id": "65bac13912032ee4eae1d47f", "testDateTime": "2024-01-31T21:52:57.185+00:00", "testId": 20 } ]
Testers
[ { "_id": "65bc139856f9734f1d19285d", "name": "FooBar Bizzle", "testResponses": [7, 19] }, { "_id": "65bc139856f9734f1d19285e", "name": "Baz Bar", "testResponses": [20] } ]
当前聚合管道(存在硬编码问题)
[ { "$project": { "lastTest": { "$arrayElemAt": [ "$testResponses", { "$indexOfArray": [ "$testResponses", { "$max": "$testResponses" } ] } ] }, "name": 1 } }, { "$match": { "lastTest": { "$ne": 20 } // 此处需要替换为BulkTests的最大testId } } ]
解决方案1:单聚合管道内完成(使用$lookup)
$unionWith适用于合并两个集合的结果,这里更适合用$lookup获取全局最大testId后再筛选,完整管道如下:
db.Testers.aggregate([ // 1. 简化获取每个测试人员的lastTest { "$project": { "lastTest": { "$max": "$testResponses" }, "name": 1, "_id": 1 } }, // 2. 关联BulkTests,获取全局最大testId { "$lookup": { "from": "BulkTests", "pipeline": [ { "$group": { "_id": null, "maxTestId": { "$max": "$testId" } } } ], "as": "maxTestData" } }, // 3. 展开关联结果数组 { "$unwind": "$maxTestData" }, // 4. 筛选lastTest不等于最大testId的文档 { "$match": { "$expr": { "$ne": ["$lastTest", "$maxTestData.maxTestId"] } } }, // 5. 整理输出字段(可选) { "$project": { "name": 1, "lastTest": 1, "_id": 1 } } ])
关键说明:
- 直接用
$max取数组最大值,比原方法更简洁高效 - 通过
$lookup的子管道对BulkTests分组,一次性拿到全局最大testId - 用
$expr实现聚合字段间的比较
解决方案2:先获取最大值再传入聚合(MongoDB 5.0+)
如果不需要严格在单管道内完成,这种方法更直观且性能更优:
// 1. 单独查询获取BulkTests的最大testId const maxTestId = db.BulkTests.find().sort({ testId: -1 }).limit(1).toArray()[0].testId; // 2. 传入变量执行聚合 db.Testers.aggregate([ { "$project": { "lastTest": { "$max": "$testResponses" }, "name": 1 } }, { "$match": { "lastTest": { "$ne": maxTestId } } } ])
内容的提问来源于stack exchange,提问作者CalebT
相关产品推荐
相关产品推荐

