如何使用Mongo聚合根据model字段获取唯一文档
解决MongoDB Cars集合按model字段去重的方法
需求:从Cars集合中按model字段去重,每个model仅保留一个对应文档,集合示例数据如下:
[ { _id:'12345', model:'Honda' }, { _id:'12346', model:'Honda' }, { _id:'12347', model:'Honda' }, { _id:'12348', model:'Toyota' }, { _id:'12349', model:'Volkswagen' }, { _id:'12350', model:'Volkswagen' }, ]
方法1:聚合管道(高效推荐)
用$group按model分组,每组保留第一个文档,最后还原文档结构:
db.Cars.aggregate([ { $group: { _id: "$model", // 以model为分组依据 doc: { $first: "$$ROOT" } // 保留每组的第一个完整文档 } }, { $replaceRoot: { newRoot: "$doc" } // 将嵌套的doc转为根文档输出 } ])
如果想保留每组最后一个文档,把$first换成$last即可,也可以根据需求指定保留特定字段。
方法2:先拿唯一model再逐个查询
先获取所有不重复的model值,再遍历查询每个model的第一个文档:
// 获取所有唯一model值 const uniqueModels = db.Cars.distinct("model"); // 遍历输出每个model的第一个匹配文档 uniqueModels.forEach(model => { console.log(db.Cars.findOne({ model: model })); });
这种方法适合需要自定义筛选逻辑的场景,但数据量大时性能不如聚合管道。
方法3:创建唯一索引(永久杜绝重复)
如果想彻底避免后续插入重复model的文档,先清理现有重复数据,再创建唯一索引:
// 第一步:删除重复数据,保留每个model的第一个文档 db.Cars.aggregate([ { $group: { _id: "$model", ids: { $push: "$_id" }, count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ]).forEach(doc => { doc.ids.shift(); // 移除第一个id,保留该文档 db.Cars.deleteMany({ _id: { $in: doc.ids } }); }); // 第二步:创建model字段的唯一索引 db.Cars.createIndex({ model: 1 }, { unique: true });
创建索引后,再插入相同model的文档会直接报错,从根源解决重复问题。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

