sql >> Database >  >> NoSQL >> MongoDB

Hoe kan ik $addToSet een object aan een array toevoegen en ook $sorteren met MongoDB?

Je was een deel van de weg daarheen door de operaties die je moest doen correct te identificeren. Maar natuurlijk $sort is geen geldige wijziging voor $addToSet aangezien de MongoDB-mantra is "sets worden niet als besteld beschouwd" :

Het andere probleem hier, zoals aangegeven door de fout, is dat u niet meerdere update-operators kunt gebruiken (zoals $addToSet en $push ) op hetzelfde pad naar een eigenschap op hetzelfde moment. Er is in feite "geen opdracht" voor het uitvoeren van verschillende update-operators, dus het is geen garantie dat de $addToSet komt voor de $push . In feite werken ze waarschijnlijk parallel, daarom is de fout en dat dit niet is toegestaan.

Het antwoord is natuurlijk "twee" update-statements. Een voor de $addToSet en één om de $sort . toe te passen door een lege array te "duwen" via $each ,

Maar omdat we echt niet willen "wachten" tot elke update is voltooid, is dit waar de API voor "Bulk"-bewerkingen voor is. U kunt dus beide instructies in één . naar de server sturen stuur en ontvang een reactie:

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();

Dus dit is eigenlijk nog steeds maar één verzoek aan de server en één antwoord. Het zijn nog steeds "twee" bewerkingen, maar de overhead en de mogelijkheid dat een of andere thread de tussentijdse status van de update grijpt, is te verwaarlozen.

Er is een alternatief voor deze benadering, namelijk het verplaatsen van de "set-detectie"-logica naar de .find() deel van de update-instructie en pas dan gewoon $push toe waar de leden die aan de "set" moeten worden toegevoegd nog niet bestaan:

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();

Natuurlijk is de complicatie dat als je hier "meerdere" array-elementen toevoegt, je die $not en $elemMacth tests in een $and voorwaarde, en als "slechts één" van die elementen geldig was, kon deze niet alleen worden toegevoegd.

U kunt dat soort bewerking "eerst" met "meerdere" items "proberen", maar dan moet u moeten hebben een "terugval"-uitvoering van elk afzonderlijk array-element met dezelfde logica als hierboven om de mogelijkheid van "duwen" voor elk element te "testen".

Dus $addToSet maakt dat tweede deel gemakkelijk met meerdere array-items. Voor één item is het vrij eenvoudig om gewoon te "vragen" en $push , voor meer dan één is het waarschijnlijk het kortere pad om het "eerste" patroon te gebruiken met $addToSet en $push een lege array om het resultaat te "sorteren", aangezien het toepassen van het tweede patroon sowieso meerdere updatetests betekent.




  1. Microsoft.Extensions.Caching.Redis selecteer een andere database dan db0

  2. Schrijft MongoDB $set alleen het veld of het hele document?

  3. het afhandelen van naamruimtewijzigingen tijdens deserialisatie van JSON String

  4. Redis haalt alle waarde van de lijst op zonder iteratie en zonder popping