Концепция здесь состоит в том, чтобы прокрутить вашу коллекцию с помощью курсора и для каждого документа в курсоре, собрать данные о позиции индекса элементов массива факторов. Затем вы будете использовать эти данные позже в цикле в качестве параметров операции обновления, чтобы правильно идентифицировать нужное поле для обновления.
Предположив ваша коллекция не так огромен, интуиция выше, может быть реализована с использованием метода курсора forEach()
, как вы сделали в попытках сделать итерацию и получать данные индекса для всех массивов, участвующих. Ниже демонстрирует этот подход для небольших наборов данных:
db.cases.find({"factors.value": { "$exists": true, "$type": 2 }}).forEach(function(doc){
var factors = doc.factors,
updateOperatorDocument = {};
for (var idx = 0; idx < factors.length; idx++){
var val;
if(factors[idx].name == "f2"){
val = !isNaN(factors[idx].value) ? parseInt(factors[idx].value) : factors[idx].value;
updateOperatorDocument["factors."+ idx +".value"] = val;
}
};
db.cases.updateOne(
{ "_id": doc._id },
{ "$set": updateOperatorDocument }
);
});
Теперь для повышения производительности, особенно при работе с большими коллекциями, воспользоваться помощью Bulk()
API для обновления коллекции навалом. Это довольно эффективно, в отличие от вышеуказанных операций, потому что с помощью API bulp вы будете отправлять операции на сервер пакетами (например, размер партии 1000), что дает вам намного лучшую производительность , так как вы не будете отправлять каждый запрос на сервер, но только раз в каждые 1000 запросов, что делает ваши обновления более эффективными и быстрыми.
Следующие примеры демонстрируют, используя Bulk()
API доступны в MongoDB версиях >= 2.6
и < 3.2
.
var bulkUpdateOps = db.cases.initializeUnOrderedBulkOp(),
counter = 0;
db.cases.find({"factors.value": { "$exists": true, "$type": 2 }}).forEach(function(doc){
var factors = doc.factors,
updateOperatorDocument = {};
for (var idx = 0; idx < factors.length; idx++){
var val;
if(factors[idx].name == "f2"){
val = !isNaN(factors[idx].value) ? parseInt(factors[idx].value) : factors[idx].value;
updateOperatorDocument["factors."+ idx +".value"] = val;
}
};
bulkUpdateOps.find({ "_id": doc._id }).update({ "$set": updateOperatorDocument })
counter++; // increment counter for batch limit
if (counter % 1000 == 0) {
// execute the bulk update operation in batches of 1000
bulkUpdateOps.execute();
// Re-initialize the bulk update operations object
bulkUpdateOps = db.cases.initializeUnOrderedBulkOp();
}
})
// Clean up remaining operation in the queue
if (counter % 1000 != 0) { bulkUpdateOps.execute(); }
Следующий пример относится к новой MongoDB версии 3.2, который с тех пор deprecated в Bulk()
API и при условии, более новый набор API-интерфейсов, использующих bulkWrite()
.
Он использует те же курсоры, как описаны выше, но и создает массивы с объемными операциями с использованием тех же forEach()
метод курсора, чтобы подтолкнуть каждый объемный документ на запись в массив.Поскольку команда записи не могут принимать не более 1000 операций, вы должны группировать операции, чтобы иметь максимум 1000 операций и повторно intialise массив, когда петля попала в 1000 итерации:
var cursor = db.cases.find({"factors.value": { "$exists": true, "$type": 2 }}),
bulkUpdateOps = [];
cursor.forEach(function(doc){
var factors = doc.factors,
updateOperatorDocument = {};
for (var idx = 0; idx < factors.length; idx++){
var val;
if(factors[idx].name == "f2"){
val = !isNaN(factors[idx].value) ? parseInt(factors[idx].value) : factors[idx].value;
updateOperatorDocument["factors."+ idx +".value"] = val;
}
};
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": updateOperatorDocument }
}
});
if (bulkUpdateOps.length == 1000) {
db.cases.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.cases.bulkWrite(bulkUpdateOps); }
запись Результат для выборки данных
{
"acknowledged" : true,
"deletedCount" : 0,
"insertedCount" : 0,
"matchedCount" : 2,
"upsertedCount" : 0,
"insertedIds" : {},
"upsertedIds" : {}
}
Ваш ответ отсутствует. Вам также необходимо выполнить операцию массового обновления в партиях 1000 * в цикле forEach в 3.2, а затем перезапустить массив. – styvane
Вы правы, хотя общий случай здесь [операции оболочки mongo не имеют этого ограничения] (https://docs.mongodb.com/manual/reference/limits/#Write-Command-Operation-Limit-Size). – chridam
Ну! Я никогда не читал эту строку раньше. Хорошо знать. – styvane