Включить переменную строки подключения перед запросом MySQL. Например, $connt
в этом коде:
$results = mysql_query($connt, "SELECT * FROM users");
Как уже отмечалось, порядок аргументов в массиве предложения $ in не отражает порядок получения документов. Это, конечно, будет естественный порядок или выбранным порядком индекса, как показано.
Если вам нужно сохранить этот порядок, то у вас в основном есть два варианта.
Итак, скажем, что вы сопоставляли значения _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
, вы также создаете «вложенный» $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, который выглядит проще, но, скорее всего, будет работать несколько медленнее.
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;
}
}
)
И это в основном полагается на испускаемые «ключевые» значения, находящиеся в «индексном порядке» того, как они встречаются во входе array.
Таким образом, это, по сути, ваши способы поддержания порядка списка входных данных в $in
, когда у вас уже есть этот список в определенном порядке.
Легкий способ упорядочить результат после того, как mongo возвращает массив, состоит в том, чтобы сделать объект с идентификатором в качестве ключей, а затем отобразить на заданный _id, чтобы вернуть упорядоченный массив.
async function batchUsers(Users, keys) {
const unorderedUsers = await Users.find({_id: {$in: keys}}).toArray()
let obj = {}
unorderedUsers.forEach(x => obj[x._id]=x)
const ordered = keys.map(key => obj[key])
return ordered
}
Я знаю, что это старый поток, но если вы просто возвращаете значение Id в массиве, возможно, вам придется выбрать этот синтаксис. Поскольку мне не показалось, что значение indexOf соответствует формату Mongo ObjectId.
obj.map = function() {
for(var i = 0; i < inputs.length; i++){
if(this._id.equals(inputs[i])) {
var order = i;
}
}
emit(order, {doc: this});
};
Как преобразовать mongo ObjectId .toString без включения 'ObjectId ()' wrapper - только значение?
Вы можете гарантировать порядок с $ или предложением.
. Вместо этого используйте $or: [ _ids.map(_id => ({_id}))]
.
Всегда? Никогда. Порядок всегда один и тот же: неопределенный (возможно, физический порядок хранения документов). Если вы не сортируете его.
Если вы не хотите использовать aggregate
, другое решение должно использовать find
, а затем сортировать результаты на стороне клиента с помощью array#sort
:
Если значения $in
являются примитивными типами, такими как числа, вы можете использовать такой подход, как:
var ids = [4, 2, 8, 1, 9, 3, 5, 6];
MyModel.find({ _id: { $in: ids } }).exec(function(err, docs) {
docs.sort(function(a, b) {
// Sort docs by the order of their _id values in ids.
return ids.indexOf(a._id) - ids.indexOf(b._id);
});
});
Если значения $in
являются непримитивными типами, например ObjectId
s, требуется другой подход поскольку indexOf
сравнивается по ссылке в этом случае.
Если вы используете Node.js 4.x +, вы можете использовать Array#findIndex
и ObjectID#equals
, чтобы отрегулировать это, изменив функцию sort
на:
docs.sort((a, b) => ids.findIndex(id => a._id.equals(id)) -
ids.findIndex(id => b._id.equals(id)));
Или с любой версией Node.js, с подчеркиванием / lodash's findIndex
:
docs.sort(function (a, b) {
return _.findIndex(ids, function (id) { return a._id.equals(id); }) -
_.findIndex(ids, function (id) { return b._id.equals(id); });
});
Другой способ использования запроса агрегирования применим только для версии MongoDB> 3.4 -
. Благодарим вас за это сообщение .
Примеры документов для выбирается в этом порядке -
var order = [ "David", "Charlie", "Tess" ];
Запрос -
var query = [
{$match: {name: {$in: order}}},
{$addFields: {"__order": {$indexOfArray: [order, "$name" ]}}},
{$sort: {"__order": 1}}
];
var result = db.users.aggregate(query);
Еще одна цитата из сообщения, объясняющая эти операторы агрегирования -
Этап «$ addFields» является новым в версии 3.4 и позволяет вам «создавать» новые поля для существующих документов, не зная всех других существующих полей. Новое выражение «$ indexOfArray» возвращает позицию определенного элемента в заданном массиве.
blockquote>В основном оператор
addToSet
добавляет новое полеorder
в каждый документ, когда он его находит, и это Полеorder
представляет собой первоначальный порядок нашего массива, который мы предоставили. Затем мы просто сортируем документы на основе этого поля.
Это решение кода после того, как результаты получены из Mongo. Использование карты для хранения индекса и затем замены значений.
catDetails := make([]CategoryDetail, 0)
err = sess.DB(mdb).C("category").
Find(bson.M{
"_id": bson.M{"$in": path},
"is_active": 1,
"name": bson.M{"$ne": ""},
"url.path": bson.M{"$exists": true, "$ne": ""},
}).
Select(
bson.M{
"is_active": 1,
"name": 1,
"url.path": 1,
}).All(&catDetails)
if err != nil{
return
}
categoryOrderMap := make(map[int]int)
for index, v := range catDetails {
categoryOrderMap[v.Id] = index
}
counter := 0
for i := 0; counter < len(categoryOrderMap); i++ {
if catId := int(path[i].(float64)); catId > 0 {
fmt.Println("cat", catId)
if swapIndex, exists := categoryOrderMap[catId]; exists {
if counter != swapIndex {
catDetails[swapIndex], catDetails[counter] = catDetails[counter], catDetails[swapIndex]
categoryOrderMap[catId] = counter
categoryOrderMap[catDetails[swapIndex].Id] = swapIndex
}
counter++
}
}
}