MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Remover duplicatas do MongoDB


O "dropDups" a sintaxe para criação de índice foi "descontinuada" a partir do MongoDB 2.6 e removida no MongoDB 3.0. Não é uma boa ideia na maioria dos casos usar isso, pois a "remoção" é arbitrária e qualquer "duplicata" pode ser removida. O que significa que o que é "removido" pode não ser o que você realmente deseja remover.

De qualquer forma, você está se deparando com um erro de "comprimento do índice", pois o valor da chave de índice aqui seria mais longo do que o permitido. De um modo geral, você não está "destinado" a indexar 43 campos em qualquer aplicativo normal.

Se você deseja remover os "duplicados" de uma coleção, sua melhor aposta é executar uma consulta de agregação para determinar quais documentos contêm dados "duplicados" e, em seguida, percorrer essa lista removendo "todos, exceto um" dos já "únicos" _id valores da coleção de destino. Isso pode ser feito com operações "em massa" para máxima eficiência.

OBSERVAÇÃO :Acho difícil acreditar que seus documentos realmente contenham 43 campos "únicos". É provável que "tudo que você precisa" é simplesmente identificar somente os campos que tornam o documento "único" e, em seguida, siga o processo conforme descrito abaixo:
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();

Se você tiver uma versão do MongoDB "inferior" a 2.6 e não tiver operações em massa, tente com o padrão .remove() dentro do laço também. Observando também que .aggregate() não retornará um cursor aqui e o loop deve mudar para:
db.testkdd.aggregate([
   // pipeline as above
]).result.forEach(function(doc) {
    doc.ids.shift();  
    db.testkdd.remove({ "_id": { "$in": doc.ids } });
});

Mas certifique-se de examinar seus documentos de perto e incluir apenas "apenas" os campos "únicos" que você espera que façam parte do agrupamento _id . Caso contrário, você acaba não removendo nada, pois não há duplicatas lá.