Som nævnt afspejler rækkefølgen af argumenterne i rækken af en $in-sætning ikke rækkefølgen af, hvordan dokumenterne hentes. Det vil selvfølgelig være den naturlige rækkefølge eller efter den valgte indeksrækkefølge som vist.
Hvis du har brug for at bevare denne rækkefølge, har du grundlæggende to muligheder.
Så lad os sige, at du matchede værdierne for _id
i dine dokumenter med et array, der vil blive sendt til $in
som [ 4, 2, 8 ]
.
Tilgang ved hjælp af 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 } }
])
Så det ville være den udvidede form. Det, der grundlæggende sker her, er, at ligesom rækken af værdier sendes til $in
du konstruerer også en "indlejret" $cond
erklæring for at teste værdierne og tildele en passende vægt. Da denne "vægt"-værdi afspejler rækkefølgen af elementerne i arrayet, kan du derefter overføre værdien til et sorteringstrin for at få dine resultater i den påkrævede rækkefølge.
Selvfølgelig "bygger" du faktisk pipeline-sætningen i kode, meget som denne:
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 );
Tilgang ved hjælp af mapReduce
Hvis det hele ser ud til at være tungt for dine følelser, kan du selvfølgelig gøre det samme ved at bruge mapReduce, som ser enklere ud, men sandsynligvis vil køre noget langsommere.
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;
}
}
)
Og det afhænger grundlæggende af, at de udsendte "nøgle"-værdier er i "indeksrækkefølgen" af, hvordan de forekommer i input-arrayet.
Så det er i bund og grund dine måder at opretholde rækkefølgen af en inputliste til en $in
tilstand, hvor du allerede har denne liste i en bestemt rækkefølge.