MongoDB按startDate保留重复Hash最旧文档的查询问题
解决MongoDB同Hash去重并保留最早startDate记录的问题
问题背景
需求:对集合中Hash字段重复(数量>1)的文档去重,仅保留startDate最早的记录。
原查询的问题在于:
- 使用
$addToSet收集_id,集合是无序结构,导致dups数组顺序随机; $sort阶段放在$group之后,此时分组结果中无startDate字段,排序完全无效,无法保证保留最早记录。
修正后的查询代码
db.Mydb.aggregate([ // 先按Hash分组,再按startDate升序排序,确保同Hash下最早的记录排在首位 { "$sort": { "Hash": 1, "startDate": 1 } }, { "$group": { "_id": "$Hash", "keepId": { "$first": "$_id" }, // 保留startDate最早的文档ID "allIds": { "$push": "$_id" }, // 收集当前Hash下所有文档ID "count": { "$sum": 1 } } }, // 仅处理存在重复的分组 { "$match": { "count": { "$gt": 1 } } }, // 筛选出需要删除的ID(排除要保留的ID) { "$project": { "deleteIds": { "$filter": { "input": "$allIds", "cond": { "$ne": ["$$this", "$keepId"] } } } } } ]).forEach(function(doc) { if (doc.deleteIds.length > 0) { db.Mydb.deleteMany({ "_id": { "$in": doc.deleteIds } }); } })
关键逻辑说明
- 排序前置:在分组前先按
Hash和startDate升序排序,确保同Hash分组内,最早的记录处于序列头部; - 精准保留:通过
$first获取分组头部的_id,即为需要保留的最早记录ID; - 批量删除:用
$filter排除保留ID,得到所有需要删除的ID列表,批量执行删除操作。
这样就能确保每个重复Hash分组中,仅保留startDate最早的文档,其余重复项被准确删除。
内容的提问来源于stack exchange,提问作者Pranav Malode
相关产品推荐
相关产品推荐

