Nejúčinnější způsob, jak toho dosáhnout, je v nadcházející verzi MongoDB v době psaní tohoto článku pomocí $split
operátora k rozdělení našeho řetězce, jak je zobrazeno zde
pak přiřaďte poslední prvek v poli proměnné pomocí $let
variabilní operátor a $arrayElemAt
operátory.
Dále použijeme $switch
operátora, který provede zpracování logické podmínky nebo příkaz case proti této proměnné.
Zde je podmínka $gt
která vrátí hodnotu true, pokud hodnota obsahuje "test"
a v tomto případě v in výraz rozdělíme tento řetězec a jednoduše vrátíme $concat
entovaná hodnota prvního prvku v nově vypočítaném poli a -
. Pokud se podmínka vyhodnotí jako nepravda, vrátíme pouze proměnnou.
V našem případě samozřejmě používáme $indexOfCP
což vrátí -1
pokud nebyly žádné výskyty "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"
}
}
}
}
}}
]
)
Agregační dotaz vytvoří něco takového:
{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" }
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" }
Jak vidíte, data pole "verze" jsou řetězce. Pokud na datovém typu pro toto pole nezáleží, můžete jednoduše použít $out
operátor fáze agregačního kanálu pro zapsání výsledku do nové kolekce nebo nahrazení vaší kolekce.
{ "out": "collection" }
Pokud potřebujete převést data na číslo s plovoucí desetinnou čárkou, jediným způsobem, jak to udělat, jednoduše proto, že MongoDB neposkytuje způsob, jak provést převod typu hned po vybalení, s výjimkou celého čísla na řetězec, je iterace agregačního kurzoru objekt a převeďte svou hodnotu pomocí parseFloat
nebo Number
poté aktualizujte své dokumenty pomocí $set
operátor a bulkWrite()
metoda pro maximální efektivitu.
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);
}
Zatímco agregační dotaz bude perfektně fungovat v MongoDB 3.4 nebo novějším, naše nejlepší sázka od MongoDB 3.2 zpět je mapReduce
pomocí bulkWrite()
metoda.
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
vypadá takto:
[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]
Odtud použijete předchozí .forEach
smyčka pro aktualizaci vašich dokumentů.
Od MongoDB 2.6 do 3.0 budete muset použít nyní zastaralou Bulk()
API a s ním spojená metoda, jak je uvedeno v mé odpovědi zde
.