MongoDB聚合查询:筛选双测试最新分数条件的用户userref
解决MongoDB聚合查询:匹配多测试最新分数的用户
嘿,我来帮你搞定这个查询需求!你的思路方向是对的,但之前的管道只处理了单个测试的条件,没法同时验证两个测试的最新分数。我们需要调整聚合逻辑,先保留用户的所有测试结果,再分别提取两个测试的最新分数,最后过滤符合条件的用户。
完整聚合管道代码
假设你要匹配TEST1最新分数=15且TEST2最新分数=1,对应的聚合管道如下:
[ // 新增字段,分别提取TEST1和TEST2的最新分数 { $addFields: { test1LatestScore: { $let: { vars: { test1Result: { $first: { $filter: { input: "$results", cond: { $eq: ["$$this.testref", "TEST1"] } } } } }, in: { $last: "$$test1Result.history.score" } } }, test2LatestScore: { $let: { vars: { test2Result: { $first: { $filter: { input: "$results", cond: { $eq: ["$$this.testref", "TEST2"] } } } } }, in: { $last: "$$test2Result.history.score" } } } } }, // 过滤条件:两个测试都完成(分数存在),且分数符合要求 { $match: { test1LatestScore: 15, test2LatestScore: 1, // 确保两个测试都存在(避免某个测试没完成但分数字段意外匹配的情况) "results.testref": { $all: ["TEST1", "TEST2"] } } }, // 只返回userref字段 { $project: { _id: 0, userref: 1 } } ]
管道逻辑拆解
让我一步步解释每个阶段的作用:
- $addFields阶段:
对每个用户文档,用$filter从results数组中筛选出testref为TEST1和TEST2的结果,再用$last取出对应结果中history数组的最后一个分数(也就是最新分数),分别存入test1LatestScore和test2LatestScore字段。 - $match阶段:
直接匹配两个最新分数的目标值,同时用$all确保用户的results中确实包含两个测试,避免出现用户没完成某测试但分数字段刚好匹配的极端情况。 - $project阶段:
只保留userref字段,去掉其他不需要的内容。
为什么你的原代码无法满足需求?
你之前的管道先$unwind了results,然后$match只保留TEST1的结果,这会把用户的TEST2结果全部过滤掉,自然没法同时验证TEST2的分数条件。我们的新方案不需要$unwind,而是直接在原文档上处理数组,保留所有必要信息来验证多条件。
测试你的示例数据
用你提供的测试数据:
{ users: [ { userref: "User1", results: [ { testref: "TEST1", history: [{ score: 10 }, { score: 15 }] }, { testref: "TEST2", history: [{ score: 2 }, { score: 1 }] } ] } ] }
运行上述聚合管道后,会返回:
{ "userref": "User1" }
内容的提问来源于stack exchange,提问作者EricP
相关产品推荐
相关产品推荐

