解决MongoDB中重复数据的方法

1.为什么会出现重复数据

在MongoDB中数据的存储采用了BSON(binary form of JSON)的格式,将JSON转化为二进制形式存储。对于一个文档(document),它有一个唯一的id属性,如果在插入时没有指定id,MongoDB会自动为它生成一个唯一的ObjectId作为id。

在插入数据时,如果文档中不含有id属性,则MongoDB会为其生成一个唯一的ObjectId作为id。但如果在插入时指定了id属性,则MongoDB会直接采用指定的id属性,此时如果指定的id属性值重复,则会出现重复数据。

2.检查重复数据

2.1 借助shell命令来检查

通过在MongoDB的shell中执行以下命令,可以查询出某个集合(collection)中所有的重复数据,以_books_集合为例:

db.books.aggregate([

{

$group:{

_id:{ISBN:"$ISBN"},

uniqueIds: {$addToSet: "$_id"},

count:{$sum:1}

}

},

{

$match:{

count: {"$gt":1}

}

}

])

上述代码使用了MongoDB聚合管道(aggregation pipeline)中的_group_和_match_操作,首先按照ISBN分组,然后利用$addToSet操作符将不重复的_id添加到uniqueIds数组中,最后利用$sum累计每组中文档的数量。如果count大于1,则表示该ISBN在集合中重复出现。

2.2 使用Robo 3T检查

如果不想在shell中使用命令检查重复数据,也可以使用GUI工具Robo 3T来完成。步骤如下:

连接MongoDB数据库

选择要检查的集合(collection)

点击左上角的“聚合”按钮

在右侧编辑器中输入上述聚合代码

点击右下角的“执行”按钮

3.解决重复数据

3.1 利用索引来防止重复插入

MongoDB中的索引可以有效地防止重复插入数据。可以在插入数据前先根据需要的属性建立唯一索引,这样在插入时如果数据中的唯一属性重复则会抛出错误,从而避免重复插入的出现。

以_books_集合中的ISBN字段为例,可以通过以下命令在该字段上建立唯一索引:

db.books.createIndex({ISBN:1},{unique:true})

上述代码中,数组中的“1”表示升序排列,所以建立的是升序唯一索引。如果需要建立降序唯一索引,可以用“-1”表示。

3.2 移除重复数据

如果已经存在重复数据,则需要手动移除。可以使用MongoDB的_remove_操作来删除重复数据。以_books_集合中的ISBN字段为例,可以通过以下命令移除重复数据:

db.books.remove({ISBN:"978-7-121-xx-xxxx",_id:{$ne:ObjectId(xxx)}})

上述代码中,第一个参数是查询条件,此处指定了ISBN值为“978-7-121-xx-xxxx”的重复数据;第二个参数是$ne(not equal)操作符,用来排除一个指定的ObjectId,这个ObjectId可以是任意已存在的文档的_id属性值。

3.3 批量移除重复数据

如果数据量非常大,则需要使用批量删除的方式来移除重复数据。可以使用MongoDB的_bulkWrite_操作来进行批量删除。

以下代码演示了如何利用_bulkWrite_在_books_集合中删除ISBN值重复的所有文档,只保留其中_id值最小的文档:

var bulk = db.books.initializeUnorderedBulkOp();

var cursor = db.books.aggregate([

{

$group:{

_id:{ISBN:"$ISBN"},

uniqueIds: {$addToSet: "$_id"},

count:{$sum:1}

}

},

{

$match:{

count: {"$gt":1}

}

}

]);

var duplicatedIds = [];

cursor.forEach(function(doc){

var idToRemove = doc.uniqueIds.sort()[0];

doc.uniqueIds.splice(doc.uniqueIds.indexOf(idToRemove), 1);

duplicatedIds = duplicatedIds.concat(doc.uniqueIds);

});

bulk.find({_id:{$in:duplicatedIds}}).remove();

bulk.execute();

上述代码通过查询重复数据并获取重复数据的_id属性值,然后构造一个_bulkWrite_操作,将重复数据中除了_id值最小的文档之外的所有文档全部删除。

4.总结

重复数据在MongoDB这样的NoSQL数据库中经常会出现。如果不加控制,这些重复数据会占用更多的存储空间,降低查询效率,并可能引发其他数据相关的问题。

为了避免重复数据的出现,我们可以先根据需要的属性建立唯一索引,在插入数据时如果数据中的唯一属性重复则会抛出错误,从而避免重复插入的出现。如果已经存在重复数据,则需要手动移除。可以使用MongoDB提供的_remove_操作和_bulkWrite_操作以及聚合操作来删除重复数据。

数据库标签