2016-06-21 216 views
3

按照这里的建议MongoDB: How to change the type of a field?我尝试更新我的集合以更改字段类型及其值。MongoDB将字符串类型转换为浮点类型

这里是更新查询

db.MyCollection.find({"ProjectID" : 44, "Cost": {$exists: true}}).forEach(function(doc){ 
    if(doc.Cost.length > 0){ 
     var newCost = doc.Cost.replace(/,/g, '').replace(/\$/g, ''); 
     doc.Cost = parseFloat(newCost).toFixed(2); 
     db.MyCollection.save(doc); 
     } // End of If Condition 
    }) // End of foreach 

上述查询完成后,当我运行以下命令

db.MyCollection.find({"ProjectID" : 44},{Cost:1}) 

我仍然有Cost字段作为字符串。

{ 
    "_id" : ObjectId("576919b66bab3bfcb9ff0915"), 
    "Cost" : "11531.23" 
} 

/* 7 */ 
{ 
    "_id" : ObjectId("576919b66bab3bfcb9ff0916"), 
    "Cost" : "13900.64" 
} 

/* 8 */ 
{ 
    "_id" : ObjectId("576919b66bab3bfcb9ff0917"), 
    "Cost" : "15000.86" 
} 

我在这里做错了什么?

下面是示例文件

/* 2 */ 
{ 
    "_id" : ObjectId("576919b66bab3bfcb9ff0911"), 
    "Cost" : "$7,100.00" 
} 

/* 3 */ 
{ 
    "_id" : ObjectId("576919b66bab3bfcb9ff0912"), 
    "Cost" : "$14,500.00" 
} 

/* 4 */ 
{ 
    "_id" : ObjectId("576919b66bab3bfcb9ff0913"), 
    "Cost" : "$12,619.00" 
} 

/* 5 */ 
{ 
    "_id" : ObjectId("576919b66bab3bfcb9ff0914"), 
    "Cost" : "$9,250.00" 
} 
+0

@chridam请使用此{ “_id”:ObjectId(“576919b66bab3bfcb9ff0915”), “成本”:“$ 11,531。23“ } – HaBo

+0

@ user3100115更新了示例文档 – HaBo

回答

3

问题是toFixed返回String,而不是一个Number。然后,您只需更新文档,并使用新的和不同的String

从蒙戈壳牌例子:

> number = 2.3431 
2.3431 
> number.toFixed(2) 
2.34 
> typeof number.toFixed(2) 
string 

如果你想有一个2位小数号,您必须使用类似再次对其进行分析:

db.MyCollection.find({"ProjectID" : 44, "Cost": {$exists: true}}).forEach(function(doc){ 
    if(doc.Cost.length > 0){ 
    var newCost = doc.Cost.replace(/,/g, '').replace(/\$/g, ''); 
    var costString = parseFloat(newCost).toFixed(2); 
    doc.Cost = parseFloat(costString); 
    db.MyCollection.save(doc); 
    } // End of If Condition 
}) // End of foreach 
+0

感谢您的详细解答 – HaBo

+0

不客气 –

2

按照这种模式字符串类型的货币字段转换浮动。您需要查询集合中具有“成本”字段类型字符串的所有文档。为此,您需要利用批量更新使用Bulk API。这些提供了更好的性能,因为您将批量向1000服务器发送操作,因为您不会将每个请求发送到服务器,而是每1000次请求只发送一次,因此可以提供更好的性能。

以下演示了这种方法,第一个示例使用MongoDB版本>= 2.6 and < 3.2中提供的Bulk API。它由所有Cost领域不断变化的浮动值字段更新集合中的所有 文件:

var bulk = db.MyCollection.initializeUnorderedBulkOp(), 
    counter = 0; 

db.MyCollection.find({ 
    "Cost": { "$exists": true, "$type": 2 } 
}).forEach(function (doc) { 
    var newCost = Number(doc.Cost.replace(/[^0-9\.]+/g,"")); 
    bulk.find({ "_id": doc._id }).updateOne({ 
     "$set": { "Cost": newCost } 
    }); 

    counter++; 
    if (counter % 1000 == 0) { 
     bulk.execute(); // Execute per 1000 operations 
     // re-initialize every 1000 update statements 
     bulk = db.MyCollection.initializeUnorderedBulkOp(); 
    } 
}) 
// Clean up remaining operations in queue 
if (counter % 1000 != 0) { bulk.execute(); } 

下一个例子适用于新的MongoDB 3.2版具有自deprecatedBulk API和提供使用bulkWrite()的一组更新的apis。

它使用与上述相同的游标,但使用相同的forEach()游标方法创建带批量操作的阵列,以将每个批量写入文档推送到数组。因为写命令可以接受不超过1000点的操作,你需要将你的操作有最多1000的操作和重新intialise数组时,循环打1000迭代:

var cursor = db.MyCollection.find({ "Cost": { "$exists": true, "$type": 2 } }), 
    bulkUpdateOps = []; 

cursor.forEach(function(doc){ 
    var newCost = Number(doc.Cost.replace(/[^0-9\.]+/g,"")); 
    bulkUpdateOps.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { "$set": { "Cost": newCost } } 
     } 
    }); 

    if (bulkUpdateOps.length == 1000) { 
     db.MyCollection.bulkWrite(bulkUpdateOps); 
     bulkUpdateOps = []; 
    } 
});   

if (bulkUpdateOps.length > 0) { db.MyCollection.bulkWrite(bulkUpdateOps); } 
+0

数字(...)是否保存十进制值? – HaBo

+0

是,[**'Number()'* *](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)是一个包装器对象,它允许您使用数值。 – chridam

+0

如果我可能会问什么是“$ type”的含义:2 – HaBo