Най-ефективният начин да направите това е в предстоящото издание на MongoDB към момента на писане с помощта на $split
оператор за разделяне на нашия низ като показан тук
след това присвоете последния елемент в масива на променлива с помощта на $let
променлив оператор и $arrayElemAt
оператори.
След това използваме $switch
оператор за извършване на обработка на логическо условие или оператор за случай спрямо тази променлива.
Условието тук е $gt
което връща true, ако стойността съдържа "test"
и в който случай в in израз разделяме този низ и просто връщаме $concat
определена стойност на първия елемент в новоизчисления масив и -
. Ако условието се изчисли като невярно, ние просто връщаме променливата.
Разбира се, в нашия case оператор ние използваме $indexOfCP
което връща -1
ако не е имало срещания на "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"
}
}
}
}
}}
]
)
Заявката за агрегиране създава нещо подобно:
{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" }
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" }
Както можете да видите, данните в полето "версия" са низ. Ако типът данни за това поле няма значение, тогава можете просто да използвате $out
оператор на етап на тръбопровод за агрегиране, за да запишете резултата в нова колекция или да замените вашата колекция.
{ "out": "collection" }
Ако тогава трябва да преобразувате вашите данни в число с плаваща запетая, единственият начин да направите това, просто защото MongoDB не предоставя начин за извършване на преобразуване на тип извън кутията, освен за цяло число в низ, е да повторите курсора за агрегиране обект и преобразувайте стойността си с помощта на parseFloat
или Number
след това актуализирайте документите си с помощта на $set
оператор и bulkWrite()
метод за максимална ефективност.
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);
}
Въпреки че заявката за агрегиране ще работи перфектно в MongoDB 3.4 или по-нова, нашият най-добър залог от MongoDB 3.2 назад е mapReduce
с bulkWrite()
метод.
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
изглежда така:
[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]
От тук използвате предишния .forEach
цикъл, за да актуализирате вашите документи.
От MongoDB 2.6 до 3.0 ще трябва да използвате вече отхвърления Bulk()
API и свързаният с него метод, както е показано в моя отговор тук.