Actualizar campo MongoDB usando el valor de otro campo
En MongoDB, ¿es posible actualizar el valor de un campo usando el valor de otro campo? El SQL equivalente sería algo así como:
UPDATE Person SET Name = FirstName + ' ' + LastName
Y el pseudo-código MongoDB sería:
db.person.update( {}, { $set : { name : firstName + ' ' + lastName } );
6 answers
No puede hacer referencia al documento en sí en una actualización (todavía). Tendrá que iterar a través de los documentos y actualizar cada documento utilizando una función. Vea esta respuesta para un ejemplo, o esta para el lado del servidor eval()
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:47
Usted debe iterar a través. Para su caso específico:
db.person.find().snapshot().forEach(
function (elem) {
db.person.update(
{
_id: elem._id
},
{
$set: {
name: elem.firstname + ' ' + elem.lastname
}
}
);
}
);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-28 05:24:44
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 usando el $addFields
y el $out
operadores de tuberías de agregación.
db.collection.aggregate(
[
{ "$addFields": {
"name": { "$concat": [ "$firstName", " ", "$lastName" ] }
}},
{ "$out": "collection" }
]
)
Tenga en cuenta que este 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 "type casting" necesitará el lado del cliente processing, y dependiendo de la operación, es posible que necesite usar el método find()
en lugar del método .aggreate()
.
MongoDB 3.2 y 3.0
La forma en que hacemos esto es por $project
ing nuestros documentos y utilizar el $concat
operador de agregación de cadenas para devolver la cadena concatenada.
a partir de ahí, a continuación, iterar el cursor y utilizar el $set
actualizar operador para agregar el nuevo campo a sus documentos usando operaciones masivas para máxima eficiencia.
Consulta de agregación:
var cursor = db.collection.aggregate([
{ "$project": {
"name": { "$concat": [ "$firstName", " ", "$lastName" ] }
}}
])
MongoDB 3.2 o posterior
A partir de esto, es necesario utilizar 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 es necesario utilizar el ahora obsoleto Bulk
API 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 } }
);
})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-24 18:29:10
Para una base de datos con alta actividad, puede encontrarse con problemas en los que sus actualizaciones afectan a los registros que cambian activamente y, por esta razón, recomiendo usar snapshot()
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 /
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-11 16:58:51
Probé la solución anterior, pero me pareció inadecuada para grandes cantidades de datos. Luego descubrí la función stream:
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
})
})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-03 11:44:17
Esto es lo que se nos ocurrió para copiar un campo a otro para ~150_000 registros. Tomó alrededor de 6 minutos, pero todavía es significativamente menos intensivo de recursos de lo que habría sido para instanciar e iterar sobre el mismo número 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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-08 15:07:08