Le moyen le plus efficace de le faire est dans la prochaine version de MongoDB au moment de la rédaction de cet article en utilisant le $split
opérateur pour diviser notre chaîne comme montré ici
puis affectez le dernier élément du tableau à une variable à l'aide du $let
opérateur variable et $arrayElemAt
les opérateurs.
Ensuite, nous utilisons le $switch
opérateur pour effectuer un traitement de condition logique ou une déclaration de cas sur cette variable.
La condition ici est $gt
qui renvoie true si la valeur contient "test"
, et auquel cas dans le in expression nous divisons cette chaîne et renvoyons simplement le $concat
valeur spécifiée du premier élément dans le tableau nouvellement calculé et le -
. Si la condition est fausse, nous renvoyons simplement la variable.
Bien sûr, dans notre déclaration de cas, nous utilisons le $indexOfCP
qui renvoie -1
s'il n'y avait aucune occurrence de "test"
.
let cursor = db.collection.aggregate(
[
{ "$project": {
"data": 1,
"version": {
"$let": {
"vars": {
"v": {
"$arrayElemAt": [
{ "$split": [ "$version", "." ] },
-1
]
}
},
"in": {
"$switch": {
"branches": [
{
"case": {
"$gt": [
{ "$indexOfCP": [ "$$v", "test" ] },
-1
]
},
"then": {
"$concat": [
"-",
"",
{ "$arrayElemAt": [
{ "$split": [ "$$v", "-" ] },
0
]}
]
}
}
],
"default": "$$v"
}
}
}
}
}}
]
)
La requête d'agrégation produit quelque chose comme ceci :
{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" }
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" }
Comme vous pouvez le voir, les données du champ "version" sont des chaînes. Si le type de données pour ce champ n'a pas d'importance, vous pouvez simplement utiliser le $out
Opérateur d'étape de pipeline d'agrégation pour écrire le résultat dans une nouvelle collection ou remplacer votre collection.
{ "out": "collection" }
Si vous avez besoin de convertir vos données en nombre à virgule flottante, la seule façon de le faire, simplement parce que MongoDB ne fournit pas un moyen de faire une conversion de type prête à l'emploi, sauf pour un entier en chaîne, est d'itérer l'agrégation Cursor objet et convertissez votre valeur en utilisant parseFloat
ou Number
puis mettez à jour vos documents en utilisant le $set
et l'opérateur bulkWrite()
méthode pour une efficacité maximale.
let requests = [];
cursor.forEach(doc => {
requests.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": {
"$set": {
"data": doc.data,
"version": parseFloat(doc.version)
},
"$unset": { "person": " " }
}
}
});
if ( requests.length === 1000 ) {
// Execute per 1000 ops and re-init
db.collection.bulkWrite(requests);
requests = [];
}}
);
// Clean up queues
if(requests.length > 0) {
db.coll.bulkWrite(requests);
}
Alors que la requête d'agrégation fonctionnera parfaitement dans MongoDB 3.4 ou plus récent, notre meilleur pari à partir de MongoDB 3.2 vers l'arrière est mapReduce
avec le bulkWrite()
méthode.
var results = db.collection.mapReduce(
function() {
var v = this.version.split(".")[2];
emit(this._id, v.indexOf("-") > -1 ? "-"+v.replace(/\D+/g, '') : v)
},
function(key, value) {},
{ "out": { "inline": 1 } }
)["results"];
results
ressemble à ceci :
[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]
À partir de là, vous utilisez le précédent .forEach
boucle pour mettre à jour vos documents.
De MongoDB 2.6 à 3.0, vous devrez utiliser le Bulk()
API et méthode associée comme indiqué dans ma réponse ici.