J'ai une collection dans MongoDB où il y a environ (environ 3 millions de disques). Mon exemple d'enregistrement ressemblerait à
{ "_id" = ObjectId("50731xxxxxxxxxxxxxxxxxxxx"),
"source_references" : [
"_id" : ObjectId("5045xxxxxxxxxxxxxx"),
"name" : "xxx",
"key" : 123
]
}
J'ai beaucoup d'enregistrements en double dans la collection ayant le même source_references.key
. (Par dupliquer je veux dire, source_references.key
pas le _id
).
Je souhaite supprimer les enregistrements en double en fonction de source_references.key
. Je songe à écrire du code PHP pour parcourir chaque enregistrement et à supprimer l'enregistrement, s'il existe.
Existe-t-il un moyen de supprimer les doublons dans la ligne de commande Mongo Internal?
Si vous êtes certain que le source_references.key
identifie les enregistrements en double, vous pouvez vous assurer d'un index unique avec l'option de création dropDups:true
index dans MongoDB 2.6 ou une version antérieure:
db.things.ensureIndex({'source_references.key' : 1}, {unique : true, dropDups : true})
Cela conservera le premier document unique pour chaque valeur source_references.key
et supprimera tous les documents ultérieurs qui, autrement, causeraient une violation de clé en double.
Notes IMPORTANTES:
dropDups
a été supprimée dans MongoDB 3.0 , une approche différente sera donc requise. Par exemple, vous pouvez utiliser l'agrégation comme suggéré sur: Documents dupliqués MongoDB même après avoir ajouté une clé unique . source_references.key
sera considéré comme ayant une valeur null, de sorte que les documents ultérieurs manquant le champ clé seront supprimés. Vous pouvez ajouter l’option sparse:true
index afin que l’index ne s’applique qu’aux documents comportant un champ source_references.key
.Mise en garde évidente: effectuez une sauvegarde de votre base de données et essayez-la d'abord dans un environnement de transfert si vous craignez une perte de données involontaire.
C’est la requête la plus simple que j’ai utilisée sur mon MongoDB 3.2
db.myCollection.find({}, {myCustomKey:1}).sort({_id:1}).forEach(function(doc){
db.myCollection.remove({_id:{$gt:doc._id}, myCustomKey:doc.myCustomKey});
})
Indexez votre customKey
avant de l'exécuter pour augmenter la vitesse
Supprimer les doublons par framework d'agrégation .
une. Si vous souhaitez supprimer en une fois.
var duplicates = [];
db.collectionName.aggregate([
// discard selection criteria, You can remove "$match" section if you want
{ $match: {
source_references.key: { "$ne": '' }
}},
{ $group: {
_id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties
dups: { "$addToSet": "$_id" },
count: { "$sum": 1 }
}},
{ $match: {
count: { "$gt": 1 } // Duplicates considered as count greater than one
}}
]) // You can display result until this and check duplicates
.forEach(function(doc) {
doc.dups.shift(); // First element skipped for deleting
doc.dups.forEach( function(dupId){
duplicates.Push(dupId); // Getting all duplicate ids
}
)
})
// If you want to Check all "_id" which you are deleting else print statement not needed
printjson(duplicates);
// Remove all duplicates in one go
db.collectionName.remove({_id:{$in:duplicates}})
b. Vous pouvez supprimer des documents un à un.
db.collectionName.aggregate([
// discard selection criteria, You can remove "$match" section if you want
{ $match: {
source_references.key: { "$ne": '' }
}},
{ $group: {
_id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties
dups: { "$addToSet": "$_id" },
count: { "$sum": 1 }
}},
{ $match: {
count: { "$gt": 1 } // Duplicates considered as count greater than one
}}
]) // You can display result until this and check duplicates
.forEach(function(doc) {
doc.dups.shift(); // First element skipped for deleting
db.collectionName.remove({_id : {$in: doc.dups }}); // Delete remaining duplicates
})
Bien que @ Stennie's soit une réponse valable, ce n'est pas le seul moyen. Enfait, le manuel MongoDB vous demande d’être très prudent en le faisant. Il y a deux autres options
Voici une manière un peu plus "manuelle" de le faire:
Essentiellement, commencez par obtenir une liste de toutes les clés uniques qui vous intéressent.
Effectuez ensuite une recherche à l’aide de chacune de ces clés et supprimez-la si cette recherche est supérieure à un.
db.collection.distinct("key").forEach((num)=>{
var i = 0;
db.collection.find({key: num}).forEach((doc)=>{
if (i) db.collection.remove({key: num}, { justOne: true })
i++
})
});
pip installer mongo_remove_duplicate_indexes
découvrez le code source du paquet pour mongo_remove_duplicate_indexes pour une meilleure compréhension.
Si vous avez assez de mémoire, vous pouvez faire quelque chose comme ça en scala:
cole.find().groupBy(_.customField).filter(_._2.size>1).map(_._2.tail).flatten.map(_.id)
.foreach(x=>cole.remove({id $eq x})