2016-05-19 2 views
1

Вот набор данныхКак преобразовать строку в int массива в MongoDB?

// Data 1 
{ name : 111, 
    factors : [ 
    {name:"f1", value:"dog", unit : "kg"}, 
    {name:"f2", value:"0"} 
    ] 
},// data2 
{ name : 112, 
    factors : 
    [ 
    {name:"f1", value:"cat", unit : "g"}, 
    {name:"f2", value:"13"} 
    ] 
} 
// 100,000 more data ... 

Я хотел бы, чтобы преобразовать значение коэффициента f2 быть number.

db.getCollection('cases').find({ 
     factors : { 
      $elemMatch : { 
       name : "f2", 
       value : {$type : 2} 
      } 
     } 
}).forEach(function(doc, i){ 
     doc.factors.forEach(function(factor){ 
      if(factor.name == "f2"){ 
       factor.value = !isNaN(factor.value) ? parseInt(factor.value) : factor.value; 
      } 
     }); 
     db.cases.save(factor); 
}); 

Однако он может обновлять только о 75 ~ 77 данных для каждого исполнения. Я не уверен, почему, и я думаю, проблема в том, что save() является асинхронным, поэтому мы не можем инициировать слишком много save() одновременно.

Что мне делать?

ответ

2

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

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

Ваш ответ отсутствует. Вам также необходимо выполнить операцию массового обновления в партиях 1000 * в цикле forEach в 3.2, а затем перезапустить массив. – styvane

+1

Вы правы, хотя общий случай здесь [операции оболочки mongo не имеют этого ограничения] (https://docs.mongodb.com/manual/reference/limits/#Write-Command-Operation-Limit-Size). – chridam

+1

Ну! Я никогда не читал эту строку раньше. Хорошо знать. – styvane

 Смежные вопросы

  • Нет связанных вопросов^_^