1. ホーム
  2. mongodb

[解決済み] MongoDBの$in句は順序を保証するか?

2022-10-21 18:10:05

質問

MongoDBの $in 節を使うとき、返されるドキュメントの順番は常に配列の引数の順番と同じになるのでしょうか?

どのように解決するのですか?

前述のように、$in句の配列の引数の順序は、ドキュメントが取得される方法の順序を反映しません。それはもちろん、自然な順序または示されるように選択されたインデックス順序になります。

この順序を保持する必要がある場合、基本的に2つのオプションがあります。

の値でマッチングしていたとしましょう。 _id に渡される配列と、 ドキュメント中の $in として [ 4, 2, 8 ] .

集計を用いたアプローチ


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 に渡されると同時に、quot;nested" $cond ステートメントを作成して、値をテストし、適切な重みを割り当てています。このquot;weight"値は配列内の要素の順序を反映しているので、その値をソートステージに渡すことで、必要な順序で結果を得ることができます。

もちろん、実際にコードでパイプラインステートメントを構築するには、このようにします。

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

そしてそれは基本的に、出力される "key" 値が入力配列の中でどのように発生するかの "index order" にあることに依存しています。


つまり、これらは本質的に、入力リストの順序を維持して $in 条件への入力リストの順序を維持する方法です。