Обновите поле MongoDB, используя значение другого поля

В MongoDB можно ли обновить значение поля, используя значение из другого поля? Эквивалентный SQL будет примерно таким:

UPDATE Person SET Name = FirstName + ' ' + LastName 

И псевдокод MongoDB будет:

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

Вы не можете ссылаться на сам документ в обновлении (пока). Вам нужно будет перебирать документы и обновлять каждый документ с помощью функции. См. Этот ответ для примера, или этот для серверного eval() .

Вы должны пройти через. Для вашего конкретного случая:

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

Лучший способ сделать это – использовать структуру агрегации для вычисления нашего нового поля.

MongoDB 3.4

Наиболее эффективное решение – в MongoDB 3.4 с использованием $addFields и $out .

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

Обратите внимание, что это не обновляет вашу коллекцию, а вместо этого заменяет существующую коллекцию или создает новую. Также для операций обновления, для которых требуется «литье типов», вам потребуется обработка на стороне клиента, и в зависимости от операции вам может понадобиться использовать метод find() вместо метода .aggreate() .

MongoDB 3.2 и 3.0

То, как мы это делаем, – это $project наших документов и использование оператора агрегации $concat string для возврата конкатенированной строки. we Оттуда вы затем перебираете курсор и используете оператор обновления $set чтобы добавить новое поле в свои документы, используя массовые операции для максимальной эффективности.

Запрос агрегирования:

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

MongoDB 3.2 или новее

из этого вам нужно использовать метод 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 и 3.0

Из этой версии вам нужно использовать теперь устаревший Bulk API и связанные с ним методы .

 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 } } ); }) 

Для базы данных с высокой активностью вы можете столкнуться с проблемами, когда ваши обновления влияют на активное изменение записей, и по этой причине я рекомендую использовать 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/

Я попробовал вышеуказанное решение, но я счел его непригодным для больших объемов данных. Затем я обнаружил функцию 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 }) }) 

Вот что мы придумали для копирования одного поля в другое для ~ 150_000 записей. Это заняло около 6 минут, но по-прежнему значительно менее ресурсоемким, чем это было бы для создания экземпляра и повторения одного и того же количества объектов 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) 
  • используя $ slice operator для получения последнего элемента массива в mongodb
  • Найти в двойном вложенном массиве MongoDB
  • Внутренний массив сортировки Mongodb
  • Согласование структуры агрегации mongodb по вложенным документам
  • Выполнение case-statement в структуре агрегации mongodb
  • итерация вектора, удаление некоторых элементов, как я иду
  • Наследование структуры в C ++
  • Структура объекта C ++ в памяти Vs a Struct
  • Сложение структуры в C ++
  • Наследование структуры в C
  • Совокупный $ lookup Общий размер документов в соответствующем конвейере превышает максимальный размер документа
  • Interesting Posts
    Давайте будем гением компьютера.