MongoDB如何实现带分组、内连接和嵌套条件的聚合查询统计符合要求的工人数量
这个需求完全可以通过MongoDB聚合实现,你原有查询的核心问题出在关联逻辑错误、没有提前过滤最新记录、字段路径引用错误三个方面,以下是正确的实现方案:
先明确关联关系链
- 工人最新位置:
WorkerLocationContext→ 按worker分组取最新 → 关联LocationSensor拿location→ 关联Location过滤非REST区域 - 最新温度数据:
HeatMeasureContext→ 按sensor分组取最新 → 关联MeasureSensor拿location和placementType - 两者通过
location字段关联后按温度阈值过滤
完整聚合查询代码
const limit = 27; // 可根据需求调整温度阈值 WorkerLocationContext.aggregate([ // 1. 取每个worker的最新位置记录 { $sort: { createdAt: -1 } }, { $group: { _id: "$worker", latestLocation: { $first: "$$ROOT" } }}, { $replaceRoot: { newRoot: "$latestLocation" } }, // 2. 关联LocationSensor拿到对应location ID { $lookup: { from: "locationsensors", // 需和你数据库实际集合命名一致,mongoose默认转小写复数 localField: "sensor", foreignField: "_id", as: "locationSensor" }}, { $unwind: "$locationSensor" }, // 3. 关联Location表,过滤休息区的工人 { $lookup: { from: "locations", localField: "locationSensor.location", foreignField: "_id", as: "location" }}, { $unwind: "$location" }, { $match: { "location.type": { $ne: "REST" } } }, // 4. 关联匹配对应位置的最新温度数据 { $lookup: { from: "heatmeasurecontexts", let: { workerLocationId: "$locationSensor.location" }, pipeline: [ // 4.1 取每个温度传感器的最新上报记录 { $sort: { createdAt: -1 } }, { $group: { _id: "$sensor", latestHeat: { $first: "$$ROOT" }, hmDatetime: { $first: "$createdAt" } }}, { $replaceRoot: { newRoot: "$latestHeat" } }, // 4.2 关联MeasureSensor拿到位置和安装类型 { $lookup: { from: "measuresensors", localField: "sensor", foreignField: "_id", as: "measureSensor" }}, { $unwind: "$measureSensor" }, // 4.3 只保留和当前工人位置匹配的温度数据 { $match: { $expr: { $eq: ["$measureSensor.location", "$$workerLocationId"] } } } ], as: "heatData" }}, { $unwind: "$heatData" }, // 5. 按温度阈值过滤符合要求的记录 { $match: { $or: [ { $and: [ { "heatData.measureSensor.placementType": "INTERNAL" }, { "heatData.internal": { $gte: limit } } ]}, { $and: [ { "heatData.measureSensor.placementType": "EXTERNAL" }, { "heatData.external": { $gte: limit } } ]} ] }}, // 6. 统计最终符合条件的工人总数,同时返回最新数据时间 { $group: { _id: null, workerCount: { $count: {} }, latestHeatTime: { $max: "$heatData.hmDatetime" }, latestLocationTime: { $max: "$createdAt" } }} ])
关键逻辑说明
- 所有上下文表取最新记录都采用
先按创建时间倒排,再分组取第一条的逻辑,保证只处理最新的位置和温度数据 - 多层关联均先join对应关联表再取值,避免了直接引用不存在的嵌套字段的错误
- 嵌套lookup中使用
$expr实现动态关联匹配,保证工人位置和温度数据的location严格对应 - 提前过滤休息区工人,减少后续关联的计算量
按你提供的样本数据,阈值设为27时,最终统计符合条件的工人数量为2,和样本中2个位于Location2的工人对应。
内容的提问来源于stack exchange,提问作者liegolas
相关产品推荐
相关产品推荐

