MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Supprimer les doublons de MongoDB

Les "dropDups" La syntaxe pour la création d'index a été "obsolète" à partir de MongoDB 2.6 et supprimée dans MongoDB 3.0. Ce n'est pas une très bonne idée dans la plupart des cas de l'utiliser car la "suppression" est arbitraire et tout "duplicata" peut être supprimé. Ce qui signifie que ce qui est "supprimé" n'est peut-être pas ce que vous voulez vraiment supprimer.

Quoi qu'il en soit, vous rencontrez une erreur de "longueur d'index" car la valeur de la clé d'index ici serait plus longue que ce qui est autorisé. De manière générale, vous n'êtes pas "conçu" pour indexer 43 champs dans une application normale.

Si vous souhaitez supprimer les "doublons" d'une collection, votre meilleur pari est d'exécuter une requête d'agrégation pour déterminer quels documents contiennent des données "dupliquées", puis de parcourir cette liste en supprimant "tous sauf un" déjà "uniques" _id valeurs de la collection cible. Cela peut être fait avec des opérations "en masse" pour une efficacité maximale.

REMARQUE :J'ai du mal à croire que vos documents contiennent en fait 43 champs "uniques". Il est probable que "tout ce dont vous avez besoin" est d'identifier simplement uniquement ces champs qui rendent le document « unique », puis suivez le processus décrit ci-dessous :

var bulk = db.testkdd.initializeOrderedBulkOp(),
    count = 0;

// List "all" fields that make a document "unique" in the `_id`
// I am only listing some for example purposes to follow
db.testkdd.aggregate([
    { "$group": {
        "_id": {
           "duration" : "$duration",
          "protocol_type": "$protocol_type", 
          "service": "$service",
          "flag": "$flag"
        },
        "ids": { "$push": "$_id" },
        "count": { "$sum": 1 }
    }},
    { "$match": { "count": { "$gt": 1 } } }
],{ "allowDiskUse": true}).forEach(function(doc) {
    doc.ids.shift();     // remove first match
    bulk.find({ "_id": { "$in": doc.ids } }).remove();  // removes all $in list
    count++;

    // Execute 1 in 1000 and re-init
    if ( count % 1000 == 0 ) {
       bulk.execute();
       bulk = db.testkdd.initializeOrderedBulkOp();
    }
});

if ( count % 1000 != 0 ) 
    bulk.execute();

Si vous avez une version de MongoDB "inférieure" à 2.6 et que vous n'avez pas d'opérations en masse, vous pouvez essayer avec le standard .remove() également à l'intérieur de la boucle. Notant également que .aggregate() ne renverra pas de curseur ici et la boucle doit changer en :

db.testkdd.aggregate([
   // pipeline as above
]).result.forEach(function(doc) {
    doc.ids.shift();  
    db.testkdd.remove({ "_id": { "$in": doc.ids } });
});

Mais assurez-vous de regarder attentivement vos documents et d'inclure uniquement "uniquement" les champs "uniques" que vous pensez faire partie du groupement _id . Sinon, vous finissez par ne rien supprimer du tout, car il n'y a pas de doublons ici.