Концепция решения здесь Переберите коллекции с курсором и для каждого документа в пределах курсора, сбор данных об эффективности индексное положение элементов массива Ancestors
.
После этого вы будете использовать эти данные в цикле в качестве параметров операции обновления, чтобы правильно идентифицировать элементы для обновления.
Предположив ваша коллекция не так огромен, интуиция выше, может быть реализована с использованием метода курсора forEach()
, как вы сделали в попытках сделать итерацию и получать данные индекса для всех элементов массива, участвующих.
Ниже демонстрирует этот подход для небольших наборов данных:
function isValidHexStr(id) {
var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
if(id == null) return false;
if(typeof id == "string") {
return id.length == 12 || (id.length == 24 && checkForHexRegExp.test(id));
}
return false;
};
db.users.find({"Ancestors.0": { "$exists": true, "$type": 2 }}).forEach(function(doc){
var ancestors = doc.Ancestors,
updateOperatorDocument = {};
for (var idx = 0; idx < ancestors.length; idx++){
if(isValidHexStr(ancestors[idx]))
updateOperatorDocument["Ancestors."+ idx] = ObjectId(ancestors[idx]);
};
db.users.updateOne(
{ "_id": doc._id },
{ "$set": updateOperatorDocument }
);
});
Теперь для повышения производительности, особенно при работе с большими коллекциями, воспользоваться помощью Bulk()
API для обновления коллекции навалом. Это довольно эффективно, в отличие от вышеуказанных операций, потому что с помощью API bulp вы будете отправлять операции на сервер пакетами (например, размер партии 1000), что дает вам намного лучшую производительность , так как вы не будете отправлять каждый запрос на сервер, но только раз в каждые 1000 запросов, что делает ваши обновления более эффективными и быстрыми.
Следующие примеры демонстрируют, используя Bulk()
API доступны в MongoDB версиях >= 2.6
и < 3.2
.
function isValidHexStr(id) {
var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
if(id == null) return false;
if(typeof id == "string") {
return id.length == 12 || (id.length == 24 && checkForHexRegExp.test(id));
}
return false;
};
var bulkUpdateOps = db.users.initializeUnOrderedBulkOp(),
counter = 0;
db.users.find({"Ancestors.0": { "$exists": true, "$type": 2 }}).forEach(function(doc){
var ancestors = doc.Ancestors,
updateOperatorDocument = {};
for (var idx = 0; idx < ancestors.length; idx++){
if(isValidHexStr(ancestors[idx]))
updateOperatorDocument["Ancestors."+ idx] = ObjectId(ancestors[idx]);
};
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.users.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.users.find({"Ancestors.0": { "$exists": true, "$type": 2 }}),
bulkUpdateOps = [];
cursor.forEach(function(doc){
var ancestors = doc.Ancestors,
updateOperatorDocument = {};
for (var idx = 0; idx < ancestors.length; idx++){
if(isValidHexStr(ancestors[idx]))
updateOperatorDocument["Ancestors."+ idx] = ObjectId(ancestors[idx]);
};
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": updateOperatorDocument }
}
});
if (bulkUpdateOps.length == 1000) {
db.users.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.users.bulkWrite(bulkUpdateOps); }
Wow! Благодаря! Я слышал о массовых операциях, но я подумал, что «давайте сделаем это быстро», и Bulk сделал это быстро! 0,15 с за 250 матчей! Большое спасибо! Я буду больше читать о – Raft