La mejor manera de hacerlo es en la versión 4.2+, que permite utilizar la canalización de agregación en el documento de actualización y updateOne
, updateMany
oupdate
método de recolección. Tenga en cuenta que este último ha quedado en desuso en la mayoría de los controladores de idiomas, si no en todos.
MongoDB 4.2+
La versión 4.2 también introdujo el $set
operador de etapa de canalización para el cual es un alias $addFields
. Usaré $set
aquí, ya que se mapea con lo que estamos tratando de lograr.
db.collection.<update method>(
{},
[
{"$set": {"name": { "$concat": ["$firstName", " ", "$lastName"]}}}
]
)
MongoDB 3.4+
En 3.4+ puedes usar $addFields
los $out
operadores de canalización de agregación.
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. Además, para las operaciones de actualización que requieren "conversión de tipo", necesitará un procesamiento del lado del cliente y , según la operación, es posible que deba usar el find()
método en lugar del .aggreate()
método.
MongoDB 3.2 y 3.0
La forma en que hacemos esto es $project
introduciendo nuestros documentos y utilizando el $concat
operador de agregación de cadenas para devolver la cadena concatenada. A partir de ahí, luego itera el cursor y utiliza el $set
operador de actualización para agregar el nuevo campo a sus documentos utilizando operaciones masivas para una máxima eficiencia.
Consulta de agregación:
var cursor = db.collection.aggregate([
{ "$project": {
"name": { "$concat": [ "$firstName", " ", "$lastName" ] }
}}
])
MongoDB 3.2 o más reciente
a partir de esto, debe usar el bulkWrite
método.
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
A partir de esta versión, debe utilizar la Bulk
API 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 } }
);
})
Deberías iterar. Para su caso específico:
fuente
save()
reemplaza completamente el documento. Debería usarupdate()
en su lugar.db.person.update( { _id: elem._id }, { $set: { name: elem.firstname + ' ' + elem.lastname } } );
create_guid
que solo producía un guid único por documento al iterarforEach
de esta manera (es decir, simplemente usarlocreate_guid
en unaupdate
declaraciónmutli=true
causó que se generara el mismo guid para todos los documentos). Esta respuesta funcionó perfectamente para mí. +1Aparentemente hay una manera de hacer esto eficientemente desde MongoDB 3.4, vea la respuesta de styvane .
Respuesta obsoleta a continuación
No puede hacer referencia al documento en sí en una actualización (todavía). Tendrá que recorrer los documentos y actualizar cada documento utilizando una función. Vea esta respuesta para un ejemplo, o esta para el lado del servidor
eval()
.fuente
update
operación. Esta solicitud de función relacionada aún no se ha resuelto.OPEN
.Para una base de datos con alta actividad, puede encontrarse con problemas en los que sus actualizaciones afectan a registros que cambian activamente y, por esta razón, recomiendo usar snapshot ()
http://docs.mongodb.org/manual/reference/method/cursor.snapshot/
fuente
snapshot()
:Deprecated in the mongo Shell since v3.2. Starting in v3.2, the $snapshot operator is deprecated in the mongo shell. In the mongo shell, use cursor.snapshot() instead.
enlaceCon respecto a esta respuesta , la función de instantánea está en desuso en la versión 3.6, de acuerdo con esta actualización . Entonces, en la versión 3.6 y superior, es posible realizar la operación de esta manera:
fuente
Al comenzar
Mongo 4.2
,db.collection.update()
puede aceptar una canalización de agregación, finalmente permitiendo la actualización / creación de un campo basado en otro campo:La primera parte
{}
es la consulta de coincidencia, filtrando qué documentos actualizar (en nuestro caso, todos los documentos).La segunda parte
[{ $set: { name: { ... } }]
es la tubería de agregación de actualización (tenga en cuenta los corchetes que significan el uso de una tubería de agregación).$set
es un nuevo operador de agregación y un alias de$addFields
.No lo olvide
{ multi: true }
, de lo contrario solo se actualizará el primer documento coincidente.fuente
Probé la solución anterior pero me pareció inadecuada para grandes cantidades de datos. Luego descubrí la función de transmisión:
fuente
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 requiere mucho menos recursos de lo que hubiera sido crear instancias e iterar sobre la misma cantidad de objetos rubí.
fuente
Con MongoDB versión 4.2+ , las actualizaciones son más flexibles, ya que permiten el uso de la canalización de agregación en su
update
,updateOne
yupdateMany
. Ahora puede transformar sus documentos utilizando los operadores de agregación y luego actualizarlos sin la necesidad de indicar explícitamente el$set
comando (en su lugar usamos$replaceRoot: {newRoot: "$$ROOT"}
)Aquí usamos la consulta agregada para extraer la marca de tiempo del campo ObjectID "_id" de MongoDB y actualizar los documentos (no soy un experto en SQL, pero creo que SQL no proporciona ningún ObjectID generado automáticamente que tenga una marca de tiempo, debería crear automáticamente esa fecha)
fuente
{ $replaceRoot: { newRoot: "$$ROOT" } }
; significa reemplazar el documento por sí mismo, lo cual no tiene sentido. Si reemplaza$addFields
por su alias$set
yupdateMany
cuál es uno de los aliasupdate
, entonces obtiene exactamente la misma respuesta que esta anterior.