Sebagaimana dicatat, urutan argumen dalam larik klausa $in tidak mencerminkan urutan bagaimana dokumen diambil. Itu tentu saja akan menjadi urutan alami atau dengan urutan indeks yang dipilih seperti yang ditunjukkan.
Jika Anda perlu mempertahankan pesanan ini, pada dasarnya Anda memiliki dua opsi.
Jadi katakanlah Anda cocok dengan nilai _id
di dokumen Anda dengan larik yang akan diteruskan ke $in
sebagai [ 4, 2, 8 ]
.
Pendekatan menggunakan Agregat
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 } }
])
Jadi itu akan menjadi bentuk yang diperluas. Apa yang pada dasarnya terjadi di sini adalah ketika array nilai dilewatkan ke $in
anda juga membuat $cond
"bersarang" pernyataan untuk menguji nilai-nilai dan menetapkan bobot yang sesuai. Karena nilai "bobot" tersebut mencerminkan urutan elemen dalam larik, Anda kemudian dapat meneruskan nilai tersebut ke tahap pengurutan untuk mendapatkan hasil dalam urutan yang diperlukan.
Tentu saja Anda benar-benar "membangun" pernyataan pipeline dalam kode, seperti ini:
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 );
Pendekatan menggunakan mapReduce
Tentu saja jika itu semua tampak besar dan kuat untuk kepekaan Anda, maka Anda dapat melakukan hal yang sama menggunakan mapReduce, yang terlihat lebih sederhana tetapi kemungkinan akan berjalan lebih lambat.
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;
}
}
)
Dan itu pada dasarnya bergantung pada nilai "kunci" yang dipancarkan dalam "urutan indeks" tentang bagaimana mereka muncul di larik input.
Jadi pada dasarnya itu adalah cara Anda mempertahankan urutan daftar input ke $in
kondisi di mana Anda sudah memiliki daftar itu dalam urutan yang ditentukan.