2016-10-13 5 views
1

У меня есть набор пользователей, и каждый пользователь имеет Предков массив, предыдущий разработчик сделал неправильную архитектуру БД, и теперь каждый из предков строка но должна быть в ObjectId. Он по-прежнему содержит objectId (фактически HEX объекта Id, например 558470744a73274db0f0d65d). Как я могу преобразовать каждого из предков в ObjectId? Я написал это:MongoDB обновление вложен массив Еогеасп

db.getCollection('Users').find({}).forEach(function(item){ 
    if (item.Ancestors instanceof Array){ 
     var tmp = new Array() 
     item.Ancestors.forEach(function(ancestor){ 
      if (ancestor instanceof String){ 
       tmp.push(ObjectId(ancestor)) 
      } 
      }) 
      item.Ancestors = tmp 
      db.getCollection('Users').save(item) 
    } 
}) 

Но похоже, что это работает не должным образом, и некоторые из предков теперь ObjectId, и некоторые null. А также предки могут быть пустым с самого начала. поэтому я ставлю все, что if «s

ответ

1

Концепция решения здесь Переберите коллекции с курсором и для каждого документа в пределах курсора, сбор данных об эффективности индексное положение элементов массива 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); } 
+1

Wow! Благодаря! Я слышал о массовых операциях, но я подумал, что «давайте сделаем это быстро», и Bulk сделал это быстро! 0,15 с за 250 матчей! Большое спасибо! Я буду больше читать о – Raft

1

Попробуйте, как это с помощью мангуста,

var mongoose = require('mongoose'); 

db.getCollection('Users').find({}).forEach(function(item){ 
    if (item.Ancestors instanceof Array){ 
     var tmp = new Array() 
     item.Ancestors.forEach(function(ancestor){ 
      if (ancestor instanceof String){ 
       tmp.push(mongoose.Types.ObjectId(ancestor)) 
      } 
      }) 
      item.Ancestors = tmp 
      db.getCollection('Users').save(item) 
    } 
}) 
Смежные вопросы