2016-06-21 214 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