web-dev-qa-db-fra.com

Comment supprimer les doublons basés sur une clé dans Mongodb?

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?

45
user1518659

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:

  • L'option 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
  • Tout document manquant le champ 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.

75
Stennie

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

45
Kanak Singhal

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
})
27
Somnath Muluk

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

  1. Laissez la MongoDB le faire pour vous avec l’option Réduire la carte .____.
  2. Vous faites par programme ce qui est moins efficace.
8

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++
      })
    });
1
Fernando

pip installer mongo_remove_duplicate_indexes

  1. créer un script dans n'importe quelle langue
  2. parcourir votre collection
  3. créer une nouvelle collection et créer un nouvel index dans cette collection avec la valeur unique true, rappelez-vous que cet index doit être identique à l'index, vous souhaitez supprimer les doublons de votre collection d'origine portant le même nom car, par exemple, vous avez une collection Gaming, et dans cette collection, vous avez un genre de champ contenant des doublons que vous souhaitez supprimer. Créez donc simplement une nouvelle collection db.createCollection ("cname") créez un nouvel index db.cname.createIndex ({ 'genre': 1}, unique: 1) maintenant, lorsque vous insérerez un document avec un genre similaire, seul le premier sera accepté, les autres seront rejetés avec une erreur de clé duplicae
  4. insérez maintenant les valeurs de format JSON reçues dans la nouvelle collection et gérez une exception à l’aide de la gestion des exceptions pour ex pymongo.errors.DuplicateKeyError 

découvrez le code source du paquet pour mongo_remove_duplicate_indexes pour une meilleure compréhension.

0
user7106300

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})
0
gilcu2