usar update operaciones modificar masivo documento datos como campos busquedas actualizar mongodb mongodb-query aggregation-framework

update - Actualizar el campo MongoDB usando el valor de otro campo



save en mongodb (6)

En MongoDB, ¿es posible actualizar el valor de un campo utilizando el valor de otro campo? El SQL equivalente sería algo así como:

UPDATE Person SET Name = FirstName + '' '' + LastName

Y el pseudocódigo de MongoDB sería:

db.person.update( {}, { $set : { name : firstName + '' '' + lastName } );


Aparentemente, hay una forma de hacerlo de manera eficiente desde MongoDB 3.4, vea la respuesta de styvane .

Respuesta obsoleta a continuación

No puede consultar el documento en una actualización (todavía). Deberá recorrer los documentos y actualizar cada documento utilizando una función. Vea esta respuesta para un ejemplo, o esta para eval() lado del servidor.


Deberías recorrerlo. Para su caso específico:

db.person.find().snapshot().forEach( function (elem) { db.person.update( { _id: elem._id }, { $set: { name: elem.firstname + '' '' + elem.lastname } } ); } );


Esto es lo que se nos ocurrió para copiar un campo a otro para ~ 150_000 registros. Tomó alrededor de 6 minutos, pero aún así es mucho menos intensivo en recursos de lo que habría sido crear instancias e iterar sobre la misma cantidad de objetos ruby.

js_query = %({ $or : [ { ''settings.mobile_notifications'' : { $exists : false }, ''settings.mobile_admin_notifications'' : { $exists : false } } ] }) js_for_each = %(function(user) { if (!user.settings.hasOwnProperty(''mobile_notifications'')) { user.settings.mobile_notifications = user.settings.email_notifications; } if (!user.settings.hasOwnProperty(''mobile_admin_notifications'')) { user.settings.mobile_admin_notifications = user.settings.email_admin_notifications; } db.users.save(user); }) js = "db.users.find(#{js_query}).forEach(#{js_for_each});" Mongoid::Sessions.default.command(''$eval'' => js)


La mejor manera de hacer esto es usar el marco de agregación para calcular nuestro nuevo campo.

MongoDB 3.4

La solución más eficiente está en MongoDB 3.4 utilizando los $addFields y $out $addFields pipeline.

db.collection.aggregate( [ { "$addFields": { "name": { "$concat": [ "$firstName", " ", "$lastName" ] } }}, { "$out": "collection" } ] )

Tenga en cuenta que esto no actualiza su colección, sino que reemplaza la colección existente o crea una nueva. También para las operaciones de actualización que requieren "conversión de tipo", necesitará el procesamiento del lado del cliente y , dependiendo de la operación, es posible que deba usar el método find() lugar del método .aggreate() .

MongoDB 3.2 y 3.0

La forma en que lo hacemos es $project nuestros documentos y usando el operador de agregación de cadenas $concat para devolver la cadena concatenada. a partir de ahí, luego se itera el cursor y se usa el operador de actualización $set para agregar el nuevo campo a sus documentos utilizando operaciones masivas para lograr la máxima eficiencia.

Consulta de agregación:

var cursor = db.collection.aggregate([ { "$project": { "name": { "$concat": [ "$firstName", " ", "$lastName" ] } }} ])

MongoDB 3.2 o más nuevo

a partir de esto, necesita utilizar el método bulkWrite .

var requests = []; cursor.forEach(document => { requests.push( { ''updateOne'': { ''filter'': { ''_id'': document._id }, ''update'': { ''$set'': { ''name'': document.name } } } }); if (requests.length === 500) { //Execute per 500 operations and re-init db.collection.bulkWrite(requests); requests = []; } }); if(requests.length > 0) { db.collection.bulkWrite(requests); }

MongoDB 2.6 y 3.0

Desde esta versión, debe utilizar la API Bulk ahora en desuso y sus métodos asociados .

var bulk = db.collection.initializeUnorderedBulkOp(); var count = 0; cursor.snapshot().forEach(function(document) { bulk.find({ ''_id'': document._id }).updateOne( { ''$set'': { ''name'': document.name } }); count++; if(count%500 === 0) { // Excecute per 500 operations and re-init bulk.execute(); bulk = db.collection.initializeUnorderedBulkOp(); } }) // clean up queues if(count > 0) { bulk.execute(); }

MongoDB 2.4

cursor["result"].forEach(function(document) { db.collection.update( { "_id": document._id }, { "$set": { "name": document.name } } ); })


Para una base de datos con alta actividad, es posible que tenga problemas en los que sus actualizaciones afecten a los registros que cambian activamente y, por este motivo, recomiendo el uso de instantáneas ()

db.person.find().snapshot().forEach( function (hombre) { hombre.name = hombre.firstName + '' '' + hombre.lastName; db.person.save(hombre); });

http://docs.mongodb.org/manual/reference/method/cursor.snapshot/


Probé la solución anterior pero no la encontré adecuada para grandes cantidades de datos. Entonces descubrí la función de transmisión:

MongoClient.connect("...", function(err, db){ var c = db.collection(''yourCollection''); var s = c.find({/* your query */}).stream(); s.on(''data'', function(doc){ c.update({_id: doc._id}, {$set: {name : doc.firstName + '' '' + doc.lastName}}, function(err, result) { /* result == true? */} } }); s.on(''end'', function(){ // stream can end before all your updates do if you have a lot }) })