sql >> Databáze >  >> NoSQL >> MongoDB

Zaručuje klauzule $in MongoDB objednávku

Jak bylo uvedeno, pořadí argumentů v poli klauzule $in neodráží pořadí, jak se dokumenty načítají. To bude samozřejmě přirozené pořadí nebo podle vybraného pořadí indexu, jak je znázorněno.

Pokud potřebujete zachovat toto pořadí, pak máte v zásadě dvě možnosti.

Řekněme tedy, že jste se shodovali s hodnotami _id ve vašich dokumentech s polem, které bude předáno do $in jako [ 4, 2, 8 ] .

Přistupte pomocí agregátu

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 } }

])

To by tedy byla rozšířená forma. V zásadě se zde děje to, že stejně jako je pole hodnot předáno $in také vytvoříte "vnořený" $cond příkaz k otestování hodnot a přiřazení vhodné váhy. Protože tato hodnota „váhy“ odráží pořadí prvků v poli, můžete pak tuto hodnotu předat do fáze řazení, abyste získali výsledky v požadovaném pořadí.

Samozřejmě ve skutečnosti „postavíte“ příkaz potrubí v kódu, podobně jako tento:

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

Přistupte pomocí mapReduce

Samozřejmě, pokud se to všechno zdá být pro vaši citlivost příliš náročné, pak můžete udělat totéž pomocí mapReduce, který vypadá jednodušeji, ale pravděpodobně poběží poněkud pomaleji.

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

A to v zásadě závisí na tom, že emitované hodnoty „klíče“ jsou v „pořadí indexu“, jak se vyskytují ve vstupním poli.

Takže to jsou v podstatě vaše způsoby, jak udržovat pořadí seznamu vstupů do $in stav, kdy již tento seznam máte v určeném pořadí.



  1. Převeďte řetězec na ObjectID v MongoDB

  2. Nelze najít modul 'socket.io/node_modules/redis'

  3. MongoDB $ měsíc

  4. Ukládání vlastností objektu v redis