A maneira mais eficiente de fazer isso é na próxima versão do MongoDB, usando o
$split
operador para dividir nossa string como mostrado aqui
em seguida, atribua o último elemento da matriz a uma variável usando o $let
operador de variável e o $arrayElemAt
operadores. Em seguida, usamos o
$switch
operador para executar um processamento de condição lógica ou instrução case em relação a essa variável. A condição aqui é
$gt
que retorna true se o valor contiver "test"
, e nesse caso no em expressão, dividimos essa string e simplesmente retornamos o $concat
valor enado do primeiro elemento no array recém-computado e o -
. Se a condição for avaliada como falsa, apenas retornamos a variável. Claro que em nossa declaração case, usamos o
$indexOfCP
que retorna -1
se não houver ocorrências 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"
}
}
}
}
}}
]
)
A consulta de agregação produz algo assim:
{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" }
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" }
Como você pode ver, os dados do campo "versão" são string. Se o tipo de dados para esse campo não importa, você pode simplesmente usar o
$out
operador de estágio de pipeline de agregação para gravar o resultado em uma nova coleção ou substituir sua coleção. { "out": "collection" }
Se você precisar converter seus dados em número de ponto flutuante, a única maneira de fazer isso, simplesmente porque o MongoDB não fornece uma maneira de fazer conversão de tipo fora da caixa, exceto inteiro para string, é iterar o cursor de agregação object e converta seu valor usando
parseFloat
ou Number
em seguida, atualize seus documentos usando o $set
operador e o bulkWrite()
método para máxima eficiência. 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);
}
Embora a consulta de agregação funcione perfeitamente no MongoDB 3.4 ou mais recente, nossa melhor aposta do MongoDB 3.2 para trás é
mapReduce
com o bulkWrite()
método. 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
se parece com isso:[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]
A partir daqui, você usa o
.forEach
loop para atualizar seus documentos. Do MongoDB 2.6 para o 3.0, você precisará usar o agora obsoleto
Bulk()
API e seu método associado como mostrado em minha resposta aqui.