Fuiste parte del camino al identificar correctamente las operaciones que necesitas hacer. Pero, por supuesto, $sort
no es un modificador válido para $addToSet
dado que el mantra de MongoDB es "los conjuntos no se consideran ordenados" :
El otro problema aquí, como lo indica el error, es que no puede usar varios operadores de actualización (como $addToSet
y $push
) en la misma ruta a una propiedad al mismo tiempo. De hecho, "no hay orden" para la ejecución de diferentes operadores de actualización, por lo que no hay garantía de que $addToSet
ocurre antes del $push
. De hecho, es probable que estén actuando en paralelo, razón por la cual el error y que esto no está permitido.
La respuesta, por supuesto, es "dos" declaraciones de actualización. Uno para el $addToSet
y otro para aplicar el $sort
"empujando" una matriz vacía a través de $each
,
Pero como realmente no queremos "esperar" a que se complete cada actualización, para eso está la API de operaciones "en masa". Entonces puede enviar ambas instrucciones al servidor en uno enviar y obtener uno respuesta:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({ "name": "Risas" }).update({
"$addToSet": {
"propiedades": { "name": "cola", "cantidad": 1 }
}
});
bulk.find({ "name": "Risas" }).update({
"$push": {
"propiedades": {
"$each": [ ], "$sort": { "cantidad": -1 }
}
}
});
bulk.execute();
Entonces, esto realmente sigue siendo solo una solicitud al servidor y una respuesta. Siguen siendo "dos" operaciones, pero la sobrecarga y la posibilidad de que algún subproceso se apodere del estado intermedio de la actualización es insignificante.
Hay una alternativa a este enfoque que es mover la lógica de "detección de conjuntos" a .find()
parte de la declaración de actualización y luego simplemente aplique $push
donde los miembros que se agregarán al "conjunto" aún no existen:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({
"name": "Risas",
"propiedades": {
"$not": { "$elemMatch": { "name": "cola", "cantidad": 1 } }
}
}).update({
"$push": {
"propiedades": {
"$each": [{ "name": "cola", "cantidad": 1 }], "$sort": { "cantidad": -1 }
}
}
});
bulk.execute();
Por supuesto, la complicación es que si está agregando elementos de matriz "múltiples" aquí, deberá envolver esos $not
y $elemMacth
pruebas en un $and
condición, y luego si "solo uno" de esos elementos era válido, entonces no se podía agregar solo.
Puede "probar" ese tipo de operación con elementos "múltiples" "primero", pero luego debería tenga una ejecución "alternativa" de cada elemento de matriz individual con la misma lógica que la anterior para "probar" la posibilidad de "empujar" para cada uno.
Entonces $addToSet
hace que la segunda parte sea fácil con múltiples entradas de matriz. Para una entrada, es bastante simple simplemente "consultar" y $push
, para más de uno es probablemente el camino más corto para usar el "primer" patrón con $addToSet
y $push
una matriz vacía para "ordenar" el resultado ya que aplicar el segundo patrón significa múltiples pruebas de actualización de todos modos.