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

У меня есть коллекция t1 со следующими полями в ее схеме

_id, field1, field1

Я хочу установить field2 значение field1 как sql:

update t1 set field1=field2;

Как мне это сделать в MongoDB?

Ответ 1

Здесь хорошие и плохие новости.

Плохая новость заключается в том, что AFAIK вы не можете сделать это с помощью одного вызова update() - mongo не поддерживает обращение к текущему объекту в обновлении.

Хорошая новость заключается в том, что есть другие способы сделать это, например. вы можете запустить цикл forEach:

db.item.find(conditions...).forEach( function (doc) {
  doc.field1 = doc.field2; 
  db.item.save(doc); 
});

Вы можете запускать forEach в оболочке администратора (команда "mongo" ) или с помощью некоторых методов вашего конкретного драйвера (например, в PHP, я ожидаю, что он будет работать с mongodb.execute(), как описано здесь: http://www.php.net/manual/en/mongodb.execute.php)

Ответ 2

Начиная с версии 3.4, мы можем использовать оператор конвейера агрегации $addFields для этого без обработки на стороне клиента, что является наиболее эффективным способом.

db.collection.aggregate(
    [
        { "$addFields": { "field2": "$field1" }},
        { "$out": "collection" }
    ]
)

До версии 3.4 нам нужно выполнить итерацию объекта Cursor и использовать $set, чтобы добавить новое поле с существующим Значение "field1". Для максимальной эффективности вам нужно сделать это, используя "объемную" операцию.

MongoDB 3.2 обесценивает Bulk() и связанные методы,, таким образом, с 3.2 вверх вы должны использовать метод bulkWrite.

var requests = [];
db.collection.find({}, { 'field1': 1 } ).snapshot().forEach(document => { 
    requests.push( { 
        'updateOne': {
            'filter': { '_id': document._id },
            'update': { '$set': { 'field2': document.field1 } }
        }
    });
    if (requests.length === 1000) {
        //Execute per 1000 operations and re-init
        db.collection.bulkWrite(requests);
        requests = [];
    }
});

if(requests.length > 0) {
    db.collection.bulkWrite(requests);
}

От версии 2.6 до 3.0 вы можете использовать API Bulk.

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

db.collection.find({}, { 'field1': 1 }).snapshot().forEach(function(document) { 
    bulk.find({ '_id': document._id }).updateOne( {
        '$set': { 'field2': document.field1 }
    });
    count++;
    if(count%1000 === 0) {
        // Excecute per 1000 operations and re-init
        bulk.execute();
        bulk = db.collection.initializeUnorderedBulkOp();
    }
})

// clean up queues
if(count > 0) {
    bulk.execute();
}

Ответ 3

Это можно сделать с помощью:

db.nameOfCollection.find().forEach(
    function (elem) {
        db.nameOfCollection.update(
            {
                _id: elem._id
            },
            {
                $set: {
                    field2: elem.field1
                }
            }
        );
    }
);