MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Гарантира ли клаузата $in на MongoDB

Както беше отбелязано, редът на аргументите в масива на клауза $in не отразява реда на това как се извличат документите. Това, разбира се, ще бъде естественият ред или по избрания индексен ред, както е показано.

Ако трябва да запазите този ред, тогава имате две възможности.

Така че да приемем, че сте съвпадали по стойностите на _id във вашите документи с масив, който ще бъде предаден в $in като [ 4, 2, 8 ] .

Подход с помощта на 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 } }

])

Така че това ще бъде разширената форма. Това, което основно се случва тук, е, че точно както масивът от стойности се предава на $in вие също така създавате "вложен" $cond изявление за тестване на стойностите и присвояване на подходящо тегло. Тъй като тази стойност на „тегло“ отразява реда на елементите в масива, можете да предадете тази стойност на етап на сортиране, за да получите резултатите си в необходимия ред.

Разбира се, вие всъщност "изграждате" оператора на конвейера в код, подобно на това:

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

Приближете с mapReduce

Разбира се, ако всичко това изглежда доста тежко за вашата чувствителност, тогава можете да направите същото, като използвате mapReduce, който изглежда по-прост, но вероятно ще работи малко по-бавно.

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

И това основно разчита на това, че излъчваните „ключови“ стойности са в „индексния ред“ на начина, по който се появяват във входния масив.

Така че това по същество са вашите начини да поддържате реда на входен списък към $in състояние, при което вече имате този списък в определен ред.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Довеждане на MongoDB в производство

  2. Как да премахнете напълно поле от документ на MongoDB?

  3. Mongodb:неуспешно свързване със сървъра при първото свързване

  4. MongoDB $strcasecmp

  5. mongodb 3.x драйвер за съвместимост с Android