sql >> Databasteknik >  >> NoSQL >> MongoDB

Hur kan jag $addToSet ett objekt till en array och $sortera också med MongoDB?

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.

$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å.




  1. MongoDB vs MySQL

  2. Golang / MGO -- panik:inga nåbara servrar

  3. använder kartan för att cache för cirka 5000 poster i Javascript-applikation VS Redis

  4. Mongodb hitta ett dokument med alla underdokument som uppfyller ett villkor