sql >> Database teknologi >  >> NoSQL >> MongoDB

Bestiller MongoDB's $in-klausul garantiordre

Som nævnt afspejler rækkefølgen af ​​argumenterne i rækken af ​​en $in-sætning ikke rækkefølgen af, hvordan dokumenterne hentes. Det vil selvfølgelig være den naturlige rækkefølge eller efter den valgte indeksrækkefølge som vist.

Hvis du har brug for at bevare denne rækkefølge, har du grundlæggende to muligheder.

Så lad os sige, at du matchede værdierne for _id i dine dokumenter med et array, der vil blive sendt til $in som [ 4, 2, 8 ] .

Tilgang ved hjælp af Aggregate

var list = [ 4, 2, 8 ];

db.collection.aggregate([

    // Match the selected documents by "_id"
    { "$match": {
        "_id": { "$in": [ 4, 2, 8 ] },
    },

    // Project a "weight" to each document
    { "$project": {
        "weight": { "$cond": [
            { "$eq": [ "$_id", 4  ] },
            1,
            { "$cond": [
                { "$eq": [ "$_id", 2 ] },
                2,
                3
            ]}
        ]}
    }},

    // Sort the results
    { "$sort": { "weight": 1 } }

])

Så det ville være den udvidede form. Det, der grundlæggende sker her, er, at ligesom rækken af ​​værdier sendes til $in du konstruerer også en "indlejret" $cond erklæring for at teste værdierne og tildele en passende vægt. Da denne "vægt"-værdi afspejler rækkefølgen af ​​elementerne i arrayet, kan du derefter overføre værdien til et sorteringstrin for at få dine resultater i den påkrævede rækkefølge.

Selvfølgelig "bygger" du faktisk pipeline-sætningen i kode, meget som denne:

var list = [ 4, 2, 8 ];

var stack = [];

for (var i = list.length - 1; i > 0; i--) {

    var rec = {
        "$cond": [
            { "$eq": [ "$_id", list[i-1] ] },
            i
        ]
    };

    if ( stack.length == 0 ) {
        rec["$cond"].push( i+1 );
    } else {
        var lval = stack.pop();
        rec["$cond"].push( lval );
    }

    stack.push( rec );

}

var pipeline = [
    { "$match": { "_id": { "$in": list } }},
    { "$project": { "weight": stack[0] }},
    { "$sort": { "weight": 1 } }
];

db.collection.aggregate( pipeline );

Tilgang ved hjælp af mapReduce

Hvis det hele ser ud til at være tungt for dine følelser, kan du selvfølgelig gøre det samme ved at bruge mapReduce, som ser enklere ud, men sandsynligvis vil køre noget langsommere.

var list = [ 4, 2, 8 ];

db.collection.mapReduce(
    function () {
        var order = inputs.indexOf(this._id);
        emit( order, { doc: this } );
    },
    function() {},
    { 
        "out": { "inline": 1 },
        "query": { "_id": { "$in": list } },
        "scope": { "inputs": list } ,
        "finalize": function (key, value) {
            return value.doc;
        }
    }
)

Og det afhænger grundlæggende af, at de udsendte "nøgle"-værdier er i "indeksrækkefølgen" af, hvordan de forekommer i input-arrayet.

Så det er i bund og grund dine måder at opretholde rækkefølgen af ​​en inputliste til en $in tilstand, hvor du allerede har denne liste i en bestemt rækkefølge.



  1. Spring Data Mongo Repository::Fælles delt metode på tværs af alle Repo-spørgsmål

  2. MongoDB forespørger optimering

  3. Godkendelse under forbindelse til MongoDB-serverinstans ved hjælp af Java

  4. Lagring af kataloghierarki i et nøgleværdidatalager