2012-02-29 15 views
46

Supponiamo di disporre di una raccolta con alcuni set di documenti. qualcosa come questo.Trova tutti i documenti duplicati in una raccolta MongoDB da un campo chiave

{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":1, "name" : "foo"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":2, "name" : "bar"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":3, "name" : "baz"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":4, "name" : "foo"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":5, "name" : "bar"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":6, "name" : "bar"} 

Desidero trovare tutte le voci duplicate in questa raccolta dal campo "nome". Per esempio. "foo" appare due volte e "bar" appare 3 volte.

+0

Per la rimozione dei duplicati è possibile utilizzare [questa soluzione] (http: // StackOverflow.it/a/33364353/1045444) –

risposta

16

Nota: questa soluzione è la più semplice da capire, ma non la migliore.

È possibile utilizzare mapReduce per scoprire quante volte un documento contiene un determinato campo:

var map = function(){ 
    if(this.name) { 
     emit(this.name, 1); 
    } 
} 

var reduce = function(key, values){ 
    return Array.sum(values); 
} 

var res = db.collection.mapReduce(map, reduce, {out:{ inline : 1}}); 
db[res.result].find({value: {$gt: 1}}).sort({value: -1}); 
5

Per una soluzione generica Mongo, vedere la MongoDB cookbook recipe for finding duplicates using group. Si noti che l'aggregazione è più veloce e più potente in quanto può restituire i _id s dei record duplicati.

Per , la risposta accettata (utilizzando mapReduce) non è efficiente. Invece, possiamo usare il metodo group:

$connection = 'mongodb://localhost:27017'; 
$con  = new Mongo($connection); // mongo db connection 

$db   = $con->test; // database 
$collection = $db->prb; // table 

$keys  = array("name" => 1); Select name field, group by it 

// set intial values 
$initial = array("count" => 0); 

// JavaScript function to perform 
$reduce  = "function (obj, prev) { prev.count++; }"; 

$g   = $collection->group($keys, $initial, $reduce); 

echo "<pre>"; 
print_r($g); 

uscita sarà questo:

Array 
(
    [retval] => Array 
     (
      [0] => Array 
       (
        [name] => 
        [count] => 1 
       ) 

      [1] => Array 
       (
        [name] => MongoDB 
        [count] => 2 
       ) 

     ) 

    [count] => 3 
    [keys] => 2 
    [ok] => 1 
) 

La query SQL equivalente sarebbe: SELECT name, COUNT(name) FROM prb GROUP BY name. Si noti che abbiamo ancora bisogno di filtrare gli elementi con un conteggio di 0 dall'array. Anche in questo caso, fare riferimento allo MongoDB cookbook recipe for finding duplicates using group per la soluzione canonica utilizzando group.

+0

Il collegamento al ricettario MongoDB è obsoleto e restituisce 404. – udachny

131

La risposta accettata è terribilmente lenta per le raccolte di grandi dimensioni e non restituisce i _id s dei record duplicati.

L'aggregazione è molto più veloce e in grado di restituire i _id s:

db.collection.aggregate([ 
    { $group: { 
    _id: { name: "$name" }, // replace `name` here twice 
    uniqueIds: { $addToSet: "$_id" }, 
    count: { $sum: 1 } 
    } }, 
    { $match: { 
    count: { $gte: 2 } 
    } }, 
    { $sort : { count : -1} }, 
    { $limit : 10 } 
]); 

Nella prima fase della pipeline aggregazione, l'operatore $group aggrega i documenti in base al campo name e negozi in uniqueIds ogni valore _id della record raggruppati. L'operatore $sum somma i valori dei campi passati ad esso, in questo caso la costante 1 - contando quindi il numero di record raggruppati nel campo count.

Nella seconda fase della pipeline, viene utilizzato $match per filtrare i documenti con uno count di almeno 2, ovvero i duplicati.

Poi, abbiamo ordinare i duplicati più frequenti prima e limitare i risultati al top 10.

Questa query sarà in uscita fino a $limit record con nomi duplicati, insieme con i loro _id s. Per esempio:

{ 
    "_id" : { 
    "name" : "Toothpick" 
}, 
    "uniqueIds" : [ 
    "xzuzJd2qatfJCSvkN", 
    "9bpewBsKbrGBQexv4", 
    "fi3Gscg9M64BQdArv", 
    ], 
    "count" : 3 
}, 
{ 
    "_id" : { 
    "name" : "Broom" 
    }, 
    "uniqueIds" : [ 
    "3vwny3YEj2qBsmmhA", 
    "gJeWGcuX6Wk69oFYD" 
    ], 
    "count" : 2 
} 
+0

Per rimuovere i duplicati è possibile utilizzare [questa soluzione] (http://stackoverflow.com/a/33364353/1045444) –

+0

Ora come può Lo chiamo usando C#? – blueprintChris

+0

Questa soluzione utilizza l'indice esistente sulla chiave? La mia preoccupazione è quella di eseguire questo contro raccolte molto grandi, in cui i documenti raggruppati potrebbero non rientrare nella memoria. – Iravanchi

Problemi correlati