Du var en del av vägen dit genom att korrekt identifiera de operationer du behöver göra. Men naturligtvis $sort
är inte en giltig modifierare för $addToSet
eftersom MongoDB-mantrat är "uppsättningar anses inte vara beställda" :
Det andra problemet här som indikeras av felet är att du inte kan använda flera uppdateringsoperatorer (som $addToSet
och $push
) på samma väg till en fastighet samtidigt. Det finns faktiskt "ingen ordning" för exekvering av olika uppdateringsoperatörer, så de är ingen garanti för att $addToSet
inträffar före $push
. Faktum är att de sannolikt agerar parallellt, vilket är anledningen till felet och att detta inte är tillåtet.
Svaret är förstås "två" uppdateringssatser. En för $addToSet
och en för att tillämpa $sort
genom att "skjuta" en tom array via $each
,
Men eftersom vi verkligen inte vill "vänta" på att varje uppdatering ska slutföras, är detta vad "Bulk" operations API är till för. Så du kan skicka båda instruktionerna till servern i ett skicka och få en svar:
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();
Så detta är verkligen fortfarande bara en begäran till servern och ett svar. Det är fortfarande "två" operationer men overheaden och möjligheten att någon tråd tar tag i uppdateringens mellanläge är försumbar.
Det finns ett alternativ till detta tillvägagångssätt som är att flytta "set-detektion"-logiken till .find()
del av uppdateringssatsen och använd sedan $push
där medlemmen/medlemmarna som ska läggas till i "uppsättningen" inte redan finns:
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();
Naturligtvis är komplikationen där att om du lägger till "flera" arrayelement här måste du linda in dessa $not
och $elemMacth
testar i en $and
villkor, och om "bara ett" av dessa element var giltigt kunde det inte läggas till ensamt.
Du kan "prova" den typen av operation med "flera" objekt "först", men sedan bör ha en "fallback"-exekvering av varje enskilt arrayelement med samma logik som ovan för att "testa" möjligheten att "pusha" för var och en.
Så $addToSet
gör den andra delen enkel med flera arrayposter. För en post är det ganska enkelt att bara "fråga" och $push
, för mer än en är det förmodligen den kortare vägen att använda det "första" mönstret med $addToSet
och $push
en tom array för att "sortera" resultatet eftersom tillämpningen av det andra mönstret innebär flera uppdateringstester ändå.