如何在MongoDB中将字符串转换为数组的int?

时间:2016-05-19 05:12:14

标签: mongodb mongodb-query

这是数据集

// 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()

我该怎么办?

1 个答案:

答案 0 :(得分: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批量更新集合。 与上述操作相比,这是非常有效的,因为使用bulp API,您将批量发送操作到服务器(例如,批量大小为1000),这会让您更好 性能,因为您不会将每个请求发送到服务器,而是每1000个请求中只发送一次,从而使您的更新更加高效和快捷。

以下示例演示如何使用MongoDB版本>= 2.6< 3.2中提供的 Bulk() API。

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(); }

下一个示例适用于自deprecated Bulk() API以来的新MongoDB版本3.2,并使用 {{3}提供了一套更新的api }

它使用与上面相同的游标,但使用相同的 bulkWrite() 游标方法创建具有批量操作的数组,以将每个批量写入文档推送到数组。因为写入命令可以接受不超过1000次操作,所以您需要将操作分组以进行最多1000次操作,并在循环达到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" : {}
}