Запрос на ограничение/смещение Mongoose и счетчик
Немного нечетного в производительности запросов... Мне нужно запустить запрос, который выполняет общее количество документов, а также может возвращать набор результатов, который может быть ограничен и смещен.
Итак, у меня есть 57 документов в целом, и пользователь хочет, чтобы 10 документов смещались на 20.
Я могу подумать о двух способах этого, сначала это запрос для всех 57 документов (возвращаемых как массив), а затем использование array.slice возвращает нужные им документы. Второй вариант состоит в том, чтобы запустить 2 запроса, первый из которых использует метод count count mongo, а затем запустить второй запрос, используя mongo native $limit и $skip aggregators.
Какой, по вашему мнению, будет лучше масштабироваться? Выполнение всего этого в одном запросе или запуск двух отдельных?
Edit:
// 1 query
var limit = 10;
var offset = 20;
Animals.find({}, function (err, animals) {
if (err) {
return next(err);
}
res.send({count: animals.length, animals: animals.slice(offset, limit + offset)});
});
// 2 queries
Animals.find({}, {limit:10, skip:20} function (err, animals) {
if (err) {
return next(err);
}
Animals.count({}, function (err, count) {
if (err) {
return next(err);
}
res.send({count: count, animals: animals});
});
});
Ответы
Ответ 1
Я предлагаю вам использовать 2 запроса:
-
db.collection.count()
вернет общее количество элементов. Это значение хранится где-то в Монго, и оно не рассчитывается.
-
db.collection.find().skip(20).limit(10)
Здесь я предполагаю, что вы можете использовать сортировку по некоторому полю, поэтому не забудьте добавить индекс в это поле. Этот запрос также будет быстрым.
Я думаю, что вы не должны запрашивать все элементы и выполнять пропуски и принимать, потому что позже, когда у вас есть большие данные, у вас будут проблемы с передачей и обработкой данных.
Ответ 2
После того, как я сам решил эту проблему, я хотел бы основываться на ответе user854301.
Mongoose ^ 4.13.8 Мне удалось использовать функцию toConstructor()
которая позволила мне избежать многократного построения запроса при применении фильтров. Я знаю, что эта функция доступна и в более старых версиях, но вам придется проверить документы Mongoose, чтобы подтвердить это.
Следующее использует обещания Bluebird:
let schema = Query.find({ name: 'bloggs', age: { $gt: 30 } });
// save the query as a 'template'
let query = schema.toConstructor();
return Promise.join(
schema.count().exec(),
query().limit(limit).skip(skip).exec(),
function (total, data) {
return { data: data, total: total }
}
);
Теперь запрос подсчета вернет общее количество найденных записей, и возвращенные данные будут подмножеством общих записей.
Обратите внимание на () вокруг query(), который создает запрос.
Ответ 3
Вместо использования 2 запросов используйте агрегат в одном запросе
Совокупность "$ facet" может быть получена быстрее, общее количество и данные с пропуском и лимитом
db.collection.aggregate([
//{$sort: {...}}
//{$match:{...}}
{$facet:{
"stage1" : [
$group:{_id:null, count:{$sum:1}}
],
"stage2" : [
{ "$skip": 0}, {"$limit": 2}
]
}},
{$unwind: "$stage1"},
//output projection
{$project:{
count: "$stage1.count",
data: "$stage2"
}}
]);
Вывести следующим образом: -
[{
count: 50,
data: [
{...},
{...}
]
}]