如何在MongoDB中查询按时间倒序后开头连续相同Port ID的条目
MongoDB 实现该需求的两种方案
注意将代码中的集合名ship_port替换为你实际使用的集合名称。
方案一:MongoDB 5.0+ 单聚合查询(推荐)
使用MongoDB 5.0推出的$setWindowFields窗口函数,一次聚合即可得到结果,管道代码如下:
db.ship_port.aggregate([ // 第一步:按时间戳倒序全量排序 { $sort: { timestamp: -1 } }, // 第二步:给每行打分组标记,连续相同port_id为同一组 { $setWindowFields: { sortBy: { timestamp: -1 }, output: { group_flag: { $sum: { $cond: [ { $eq: ["$port_id", { $lag: "$port_id", default: null }] }, 0, 1 ] }, window: { documents: ["unbounded", "current"] } } } } }, // 第三步:只取第一组(开头连续相同port_id的条目) { $match: { group_flag: 0 } }, // 可选:去掉多余的group_flag字段 { $unset: "group_flag" } ])
逻辑说明:排序后逐行对比当前行和上一行的port_id,第一次出现不同时group_flag会变为1,所有group_flag=0的条目就是开头连续相同port_id的结果。
方案二:兼容低版本MongoDB的两次查询方案
如果MongoDB版本低于5.0,没有窗口函数支持,可以用两次简单查询实现,性能同样很高:
- 先查询最新的一条记录,拿到目标port_id
const latestRecord = db.ship_port.findOne({}, { sort: { timestamp: -1 } }); const targetPortId = latestRecord.port_id;
- 再查询最新的、port_id不等于目标值的记录,拿到它的时间戳
const firstDiffRecord = db.ship_port.findOne( { port_id: { $ne: targetPortId } }, { sort: { timestamp: -1 } } );
- 最后查询所有时间戳大于第一个不同记录时间戳的条目,就是需要的结果
let result; if (!firstDiffRecord) { // 所有记录port_id都相同,返回全部 result = db.ship_port.find({}).sort({ timestamp: -1 }).toArray(); } else { result = db.ship_port.find({ timestamp: { $gt: firstDiffRecord.timestamp } }).sort({ timestamp: -1 }).toArray(); }
性能优化建议
给timestamp字段建倒序索引,两种方案的查询效率都会达到最优,即使集合数据量很大也不会有性能问题。
内容的提问来源于stack exchange,提问作者Daniel Ramos
相关产品推荐
相关产品推荐

