Jak już wspomniano, kolejność argumentów w tablicy klauzuli $in nie odzwierciedla kolejności pobierania dokumentów. Będzie to oczywiście kolejność naturalna lub według wybranego porządku indeksu, jak pokazano.
Jeśli chcesz zachować tę kolejność, masz w zasadzie dwie opcje.
Załóżmy więc, że dopasowywałeś wartości _id
w dokumentach z tablicą, która zostanie przekazana do $in
jako [ 4, 2, 8 ]
.
Podejdź za pomocą agregatu
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 } }
])
To byłaby rozszerzona forma. Zasadniczo dzieje się tutaj tak, jak tablica wartości jest przekazywana do $in
konstruujesz również "zagnieżdżony" $cond
oświadczenie, aby przetestować wartości i przypisać odpowiednią wagę. Ponieważ ta wartość „waga” odzwierciedla kolejność elementów w tablicy, możesz następnie przekazać tę wartość do etapu sortowania, aby uzyskać wyniki w wymaganej kolejności.
Oczywiście faktycznie „budujesz” instrukcję potoku w kodzie, podobnie jak to:
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 );
Podejdź za pomocą mapReduce
Oczywiście, jeśli to wszystko wydaje się mocne dla twojej wrażliwości, możesz zrobić to samo za pomocą mapReduce, które wygląda na prostsze, ale prawdopodobnie będzie działać nieco wolniej.
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;
}
}
)
A to zasadniczo polega na tym, że emitowane wartości „klucza” są w „kolejności indeksu” według tego, jak występują w tablicy wejściowej.
Tak więc zasadniczo są to twoje sposoby na utrzymanie kolejności listy wejściowej do $in
stan, w którym masz już tę listę w określonej kolejności.