2011-04-03 29 views
7

Estoy utilizando MongoDB y necesito eliminar registros duplicados. Tengo una colección lista que se ve así: (simplificado)Eliminar registros duplicados usando MapReduce

[ 
    { "MlsId": "12345"" }, 
    { "MlsId": "12345" }, 
    { "MlsId": "23456" }, 
    { "MlsId": "23456" }, 
    { "MlsId": "0" }, 
    { "MlsId": "0" }, 
    { "MlsId": "" }, 
    { "MlsId": "" } 
] 

Una lista es un duplicado si el MlsId no es "" o "0" y otra lista tiene el mismo MlsId. Entonces, en el ejemplo anterior, los registros 2º y 4º deberían eliminarse.

¿Cómo puedo encontrar todas las listas duplicadas y eliminarlas? Empecé a buscar en MapReduce pero no pude encontrar un ejemplo que se ajustara a mi caso.

Esto es lo que tengo hasta ahora, pero no comprueba si el MlsId es "0" o "":

m = function() { 
    emit(this.MlsId, 1); 
} 

r = function (k, vals) { 
    return Array.sum(vals); 
} 

res = db.Listing.mapReduce(m,r); 
db[res.result].find({value: {$gt: 1}}); 
db[res.result].drop(); 

Respuesta

2

No he utilizado mongodb pero he utilizado mapreduce. Creo que estás en el camino correcto en términos de las funciones mapreduce. Para excluir él 0 y vacíos cuerdas, se puede añadir una marca en la misma función en el mapa .. algo así como

m = function() { 
    if(this.MlsId!=0 && this.MlsId!="") {  
    emit(this.MlsId, 1); 
    } 
} 

y reducir debería devolver pares de valores clave. Por lo que debe ser:

r = function(k, vals) { 
    emit(k,Arrays.sum(vals); 
} 

Después de esto, usted debe tener un conjunto de pares de valores clave en la producción de tal manera que la clave es MlsId y el valor es el número de thimes ocurre esta identificación particular. No estoy seguro acerca de la parte db.drop(). Como usted señaló, lo más probable es que borre todos los MlsIds en lugar de eliminar solo los duplicados. Para evitar esto, tal vez puedas llamar a drop() primero y luego recrear el MlsId una vez. ¿Funcionará para ti?

+0

puede que no sea capaz de responder a esto, pero si declaro las funciones M y R y luego ejecuta la función mapReduce y luego ejecuta el db [res.result] .drop(); comando, ¿va a soltar todos los listados o solo los que están duplicados? No entiendo mapReduce y emitir así que no sé cómo funciona todo esto ... – Justin

+0

He hecho una pequeña corrección para reducir(). No estoy seguro de que hoe db.drop() funcione, pero sí, supongo que eliminará todos los entried para ese ID en particular. Pero espero que tu comprensión de la parte map-reduce sea clara. Aunque no estoy seguro de la sintaxis de mongodb ... veré si puedo resolver algo. –

+0

Puede intentar agregar un índice con la opción Eliminar duplicados como se menciona aquí: http://www.mongodb.org/display/DOCS/ Índices Caerá automáticamente los valores duplicados.Otra forma es primero colocar() todos los valores y luego agregar un valor. –

2

En mongodb puede usar una consulta para restringir los documentos que se transfieren para el mapeo. Probablemente quieras hacer eso para aquellos que no te importan. Luego, en la función de reducción puede ignorar los dups y solo devolver uno de los documentos para cada clave duplicada.

Sin embargo, estoy un poco confundido acerca de su objetivo. Si solo quiere encontrar duplicados y eliminar todos menos uno de ellos, puede crear un índice único en ese campo y usar la opción dropDups; el proceso de creación del índice arrojará documentos duplicados. Mantener el índice asegurará que no vuelva a suceder.

http://www.mongodb.org/display/DOCS/Indexes#Indexes-DuplicateValues

+0

Como se mencionó anteriormente, no puedo usar el índice único con dropDups porque solo mantendría una lista con el valor "" y una lista con el valor "0", cuando quiero mantener todos estos. – Justin

-1

Puede usar la operación de agregación para eliminar duplicados. Relájate, introduce un escenario ficticio $ group y $ sum e ignora los recuentos en tu próxima etapa. Algo como esto,

db.myCollection.aggregate([ 
{ 
    $unwind: '$list' 
}, 
{ 
    $group:{ 
    '_id': 
     { 
     'listing_id':'$_id', 'MlsId':'$list.MlsId' 
     }, 
      'count': 
     { 
      '$sum':1 
     } 
     } 
}, 
{ 
     $group: 
     { 
     '_id':'$_id.listing_id', 
     'list': 
     { 
      '$addToSet': 
      { 
      'MlsId':'$_id.MlsId' 
      } 
     } 
     } 
} 
]); 
-1

así es como continuación de la respuesta @harri para eliminar duplicados:

//contains duplicated documents id and numeber of duplicates 
db.createCollection("myDupesCollection") 
res = db.sampledDB.mapReduce(m, r, { out : "myDupesCollection" }); 

// iterate through duplicated docs and remove duplicates (keep one) 
db.myDupesCollection.find({value: {$gt: 1}}).forEach(function(myDoc){ 
    u_id = myDoc._id.MlsId; 
    counts =myDoc.value; 
    db.sampledDB.remove({MlsId: u_id},counts-1); //if there are 3 docs, remove 3-1=2 of them 
}); 
Cuestiones relacionadas