La forma más eficiente de hacer esto es en la próxima versión de MongoDB a partir de este escrito usando el $split
operador para dividir nuestra cadena como que se muestra aquí
luego asigne el último elemento de la matriz a una variable usando el $let
operador variable y el $arrayElemAt
operadores.
A continuación, usamos el $switch
operador para realizar un procesamiento de condición lógica o declaración de caso contra esa variable.
La condición aquí es $gt
que devuelve verdadero si el valor contiene "test"
, y en cuyo caso en el en expresión dividimos esa cadena y simplemente devolvemos el $concat
valor generado del primer elemento en la matriz recién calculada y el -
. Si la condición se evalúa como falsa, simplemente devolvemos la variable.
Por supuesto, en nuestra declaración de caso, usamos el $indexOfCP
que devuelve -1
si no hubiera ocurrencias 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 consulta de agregación produce algo como esto:
{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" }
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" }
Como puede ver, los datos del campo "versión" son una cadena. Si el tipo de datos para ese campo no importa, simplemente puede usar el $out
operador de etapa de canalización de agregación para escribir el resultado en una nueva colección o reemplazar su colección.
{ "out": "collection" }
Si necesita convertir sus datos a un número de coma flotante, entonces, la única forma de hacerlo, simplemente porque MongoDB no proporciona una forma de hacer la conversión de tipo lista para usar, excepto de entero a cadena, es iterar el Cursor de agregación objeto y convierta su valor usando parseFloat
o Number
luego actualice sus documentos usando $set
y el operador bulkWrite()
método para la máxima eficiencia.
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);
}
Si bien la consulta de agregación funcionará perfectamente en MongoDB 3.4 o posterior, nuestra mejor apuesta desde MongoDB 3.2 hacia atrás es mapReduce
con 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 a esto:
[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]
Desde aquí, usa el .forEach
bucle para actualizar sus documentos.
De MongoDB 2.6 a 3.0 necesitará usar el ahora obsoleto Bulk()
API y su método asociado como se muestra en mi respuesta aquí.