2016-06-21 1 views
3

Suite aux suggestions ici MongoDB: How to change the type of a field? J'ai essayé de mettre à jour ma collection pour changer le type de champ et sa valeur.MongoDB convertir le type de chaîne à float type

Voici la requête de mise à jour

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 

à la fin de la requête ci-dessus, quand je lance la commande suivante

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

J'ai encore Cost champ sous forme de chaîne.

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

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

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

Qu'est-ce que je fais mal ici?

Voici le document exemple

/* 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 s'il vous plaît utiliser cette { "_id": ObjectId ("576919b66bab3bfcb9ff0915"), "Coût": "$ 11,531.23" } @ – HaBo

+0

user3100115 mis à jour avec le document exemple. – HaBo

Répondre

3

Le problème est que toFixed retourne un String, pas Number. Ensuite, vous venez de mettre à jour le document avec un nouveau, et différent String.

Exemple de Mongo Shell:

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

Si vous voulez un 2 décimales numéro que vous devez analyser à nouveau avec quelque chose comme:

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

Merci pour la réponse détaillée. – HaBo

+0

Vous êtes les bienvenus. –

2

Suivez ce modèle pour convertir un champ de monnaie de type chaîne à un flotteur. Vous devez interroger tous les documents de la collection ayant la chaîne de type de champ Coût. Pour ce faire, vous devez utiliser le Bulk API pour les mises à jour groupées. Ceux-ci offrent de meilleures performances car vous enverrez les opérations au serveur par lots de 1000, ce qui vous donne une meilleure performance car vous n'envoyez pas toutes les requêtes au serveur, mais seulement une fois par 1000 demandes.

Ce qui suit illustre cette approche, le premier exemple utilise l'API en bloc disponible dans les versions MongoDB >= 2.6 and < 3.2. Il met à jour tous les documents de la collection en changeant tous les Cost champs aux champs de valeur flottante:

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

L'exemple suivant applique à la nouvelle version MongoDB 3.2 qui a depuis deprecated la Bulk API et fourni un ensemble d'apis plus récent utilisant bulkWrite().

Il utilise les mêmes curseurs que ci-dessus mais crée les tableaux avec les opérations en bloc en utilisant la même méthode de curseur forEach() pour pousser chaque document d'écriture en bloc dans le tableau. Parce que les commandes d'écriture peuvent accepter plus de 1000 opérations, vous devrez regrouper vos opérations d'avoir au plus 1000 opérations et re-l'initialiser le tableau lors de la boucle atteint 1000 itération:

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

compteraient (...) détient des valeurs décimales? – HaBo

+0

Oui, [** 'Number()' * *] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) est un objet wrapper qui vous permet de travailler avec des valeurs numériques – chridam

+0

Si je peux demander quel est le signification de "$ type": 2 – HaBo