2012-04-06 32 views
23

Necesito reemplazar una cadena en ciertos documentos. He buscado este código en Google, pero desafortunadamente no cambia nada. No estoy seguro acerca de la sintaxis en la línea de abajo:Cómo reemplazar cadenas en todos los documentos en Mongo

pulpdb = db.getSisterDB("pulp_database"); 
var cursor = pulpdb.repos.find(); 
while (cursor.hasNext()) { 
    var x = cursor.next(); 
    x['source']['url'].replace('aaa', 'bbb'); // is this correct? 
    db.foo.update({_id : x._id}, x); 
} 

me gustaría añadir algunas impresiones de depuración para ver cuál es el valor, pero no tengo experiencias con MongoDB Shell. Sólo hay que sustituir este:

{ "source": { "url": "http://aaa/xxx/yyy" } } 

con

{ "source": { "url": "http://bbb/xxx/yyy" } } 
+0

El shell Mongo ejecuta javascript arbitrario que sugiere que el código funciona. ¿Lo has probado simplemente? – Derick

Respuesta

37

No corrige general: si tiene cadena http://aaa/xxx/aaa (yyy es igual a aaa) que va a terminar con http://bbb/xxx/bbb. Pero si está de acuerdo con esto, el código funcionará.

Para añadir información de depuración utilizar print función:

var cursor = db.test.find(); 
while (cursor.hasNext()) { 
    var x = cursor.next(); 
    print("Before: "+x['source']['url']); 
    x['source']['url'] = x['source']['url'].replace('aaa', 'bbb'); 
    print("After: "+x['source']['url']); 
    db.test.update({_id : x._id}, x); 
} 

(Y por cierto, si desea imprimir objetos, también hay printjson función)

+0

¡Oh, no intenté "imprimir" :-) así de simple! De acuerdo, puedo ver que los datos están llegando, creo que tengo un inconveniente en la expresión regular (el caso real no es xxx sino https://abc.blablab.com) – lzap

+0

Entendido - Tenía que hacer x ['source '] [' url '] = x [' fuente '] [' url ']. reemplazar (...) en su lugar. – lzap

+0

Hmm por alguna extraña razón, la variable se reemplaza pero los datos no se almacenan. ¿Necesito realizar una confirmación o algo? Todavía veo datos antiguos allí. – lzap

1

MongoDB puede hacer búsqueda de cadenas/reemplazar a través de mapreduce. Sí, necesita una estructura de datos muy especial: no puede tener nada en las teclas superiores, pero necesita almacenar todo bajo un subdocumento bajo value. De esta manera:

{ 
    "_id" : ObjectId("549dafb0a0d0ca4ed723e37f"), 
    "value" : { 
      "title" : "Top 'access denied' errors", 
      "parent" : "system.admin_reports", 
      "p" : "\u0001\u001a%" 
    } 
} 

Una vez que haya esta perfectamente establecido que puede hacer:

$map = new \MongoCode("function() { 
    this.value['p'] = this.value['p'].replace('$from', '$to'); 
    emit(this._id, this.value); 
}"); 
$collection = $this->mongoCollection(); 
// This won't be called. 
$reduce = new \MongoCode("function() { }"); 
$collection_name = $collection->getName(); 
$collection->db->command([ 
    'mapreduce' => $collection_name, 
    'map' => $map, 
    'reduce' => $reduce, 
    'out' => ['merge' => $collection_name], 
    'query' => $query, 
    'sort' => ['_id' => 1], 
]); 
+0

Este no es un enfoque correcto para el problema - mapReduce puede producir un nuevo conjunto de resultados, no debe usarse para "reemplazar" "valores existentes de esta manera. Además, depende de algo extremadamente específico: formatear su colección de esta manera solo para dar salida a _id, los pares de valores parecen mucho más complicados que la respuesta ya dada al iterar sobre documentos en el shell. –

+0

No todas las aplicaciones web tienen privilegios para ejecutar comandos de shell. Otro enfoque sería recuperar todo en PHP, reemplazar y guardar de nuevo, pero en el servidor seguramente es más rápido. Finalmente, ¿podría citar alguna documentación oficial como por qué no debería usarse de esta manera? No he leído nada que diga que no debes unirte a la fuente. – chx

+0

no está mapeando ni reduciendo :) Básicamente, está sobreescribiendo y ese no es realmente el propósito de "mapReduce" - literalmente está haciendo una actualización de cada documento. En el mejor de los casos, esto se puede describir como un truco (que solo funciona en este formato específico exacto del documento) –

1

La mejor manera de hacer esto si usted está en MongoDB 2.6 o más reciente es un bucle sobre el objeto cursor utilizando la .forEach método y actualizar cada documento utilizando "bulk" operaciones para la máxima eficiencia.

var bulk = db.collection.initializeOrderedBulkOp(); 
var count = 0; 

db.collection.find().forEach(function(doc) { 
    print("Before: "+doc.source.url); 
    bulk.find({ '_id': doc._id }).update({ 
     '$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') } 
    }) 
    count++; 
    if(count % 200 === 0) { 
     bulk.execute(); 
     bulk = db.collection.initializeOrderedBulkOp(); 
    } 

// Clean up queues 
if (count > 0) 
    bulk.execute(); 

De MongoDB 3.2 la Bulk() API y su asociado methods están en desuso que tendrá que utilizar el método db.collection.bulkWrite().

Necesitará un bucle sobre el cursor, construirá su consulta dinámicamente y $push cada operación en una matriz.

var operations = []; 
db.collection.find().forEach(function(doc) { 
    print("Before: "+doc.source.url); 
    var operation = { 
     updateOne: { 
      filter: { '_id': doc._id }, 
      update: { 
       '$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') } 
      } 
     } 
    }; 
    operations.push(operation); 
}) 
operations.push({ 
    ordered: true, 
    writeConcern: { w: "majority", wtimeout: 5000 } 
}) 

db.collection.bulkWrite(operations); 
Cuestiones relacionadas