Den mest effektive måde at gøre dette på er i den kommende udgivelse af MongoDB, når dette skrives ved hjælp af $split
operatør for at opdele vores streng som vist her
tildel derefter det sidste element i arrayet til en variabel ved hjælp af $let
variabeloperatoren og $arrayElemAt
operatører.
Dernæst bruger vi $switch
operatør til at udføre en logisk tilstandsbehandling eller sagsudsagn mod denne variabel.
Betingelsen her er $gt
som returnerer sand, hvis værdien indeholder "test"
, og i så fald i i udtryk deler vi den streng og returnerer simpelthen $concat
eneret værdi af det første element i det nyligt beregnede array og -
. Hvis betingelsen evalueres til falsk, returnerer vi bare variablen.
Selvfølgelig bruger vi i vores case-sætning $indexOfCP
som returnerer -1
hvis der ikke var nogen forekomster af "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"
}
}
}
}
}}
]
)
Aggregeringsforespørgslen producerer noget som dette:
{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" }
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" }
Som du kan se, er "version" feltdataene strenge. Hvis datatypen for det pågældende felt ikke betyder noget, kan du blot bruge $out
aggregation pipeline stage operator for at skrive resultatet ind i en ny samling eller erstatte din samling.
{ "out": "collection" }
Hvis du har brug for at konvertere dine data til et flydende decimaltal, er den eneste måde at gøre dette på, simpelthen fordi MongoDB ikke giver en måde at udføre typekonvertering ud af boksen på bortset fra heltal til streng, at iterere aggregeringsmarkøren objekt og konverter din værdi ved hjælp af parseFloat
eller Number
opdater derefter dine dokumenter ved hjælp af $set
operatøren og bulkWrite()
metode til maksimal effektivitet.
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);
}
Mens aggregeringsforespørgslen vil fungere perfekt i MongoDB 3.4 eller nyere, er vores bedste bud fra MongoDB 3.2 baglæns mapReduce
med bulkWrite()
metode.
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
ser sådan ud:
[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]
Herfra bruger du den tidligere .forEach
sløjfe for at opdatere dine dokumenter.
Fra MongoDB 2.6 til 3.0 skal du bruge den nu forældede Bulk()
API og den tilhørende metode som vist i mit svar her.