前述のように、$ in句の配列内の引数の順序は、ドキュメントの取得方法の順序を反映していません。もちろん、それは自然な順序、または示されているように選択されたインデックスの順序になります。
この順序を維持する必要がある場合は、基本的に2つのオプションがあります。
したがって、_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
への入力リストの順序を維持するための方法です。 そのリストが決まった順序ですでにある状態。