Для скорости я хотел бы ограничить запрос до 10 результатов
db.collection.find( ... ).limit(10)
Однако я также хотел бы узнать общее количество, так сказать "было 124, но у меня всего 10". Есть ли эффективный способ сделать это?
Для скорости я хотел бы ограничить запрос до 10 результатов
db.collection.find( ... ).limit(10)
Однако я также хотел бы узнать общее количество, так сказать "было 124, но у меня всего 10". Есть ли эффективный способ сделать это?
По умолчанию count()
игнорирует limit()
и подсчитывает результаты всего запроса.
Поэтому, когда вы, например, делаете это, var a = db.collection.find(...).limit(10);
запуск a.count()
даст вам общее количество вашего запроса.
Ведение счета (1) включает ограничение и пропустить.
cursor.count()
должен игнорировать cursor.skip()
и cursor.limit()
по умолчанию.
Источник: http://docs.mongodb.org/manual/reference/method/cursor.count/#cursor.count
Принятый ответ by @johnnycrab предназначен для CLI монго.
Если вам нужно написать тот же код в Node.js и Express.js, вам придется использовать его так, чтобы использовать функцию "count" вместе с результатом "toArray".
var curFind = db.collection('tasks').find({query});
Затем вы можете запускать две функции после нее (одна вложенная в другую)
curFind.count(function (e, count) {
// Use count here
curFind.skip(0).limit(10).toArray(function(err, result) {
// Use result here and count here
});
});
Существует решение с использованием push и slice: fooobar.com/info/181954/...
I prefe
Решение с нажатием $$ ROOT и использованием $slice работает с ограничением памяти документа 16 МБ для больших коллекций. Кроме того, для больших коллекций два запроса вместе работают быстрее, чем один с нажатием $$ ROOT. Вы можете запускать их параллельно, поэтому вы ограничены только медленными двумя запросами (возможно, теми, которые сортируются).
Я решил использовать это решение, используя 2 запроса и структуру агрегации (примечание - я использую node.js в этом примере, но идея такая же):
var aggregation = [
{
// If you can match fields at the begining, match as many as early as possible.
$match: {...}
},
{
// Projection.
$project: {...}
},
{
// Some things you can match only after projection or grouping, so do it now.
$match: {...}
}
];
// Copy filtering elements from the pipeline - this is the same for both counting number of fileter elements and for pagination queries.
var aggregationPaginated = aggregation.slice(0);
// Count filtered elements.
aggregation.push(
{
$group: {
_id: null,
count: { $sum: 1 }
}
}
);
// Sort in pagination query.
aggregationPaginated.push(
{
$sort: sorting
}
);
// Paginate.
aggregationPaginated.push(
{
$limit: skip + length
},
{
$skip: skip
}
);
// I use mongoose.
// Get total count.
model.count(function(errCount, totalCount) {
// Count filtered.
model.aggregate(aggregation)
.allowDiskUse(true)
.exec(
function(errFind, documents) {
if (errFind) {
// Errors.
res.status(503);
return res.json({
'success': false,
'response': 'err_counting'
});
}
else {
// Number of filtered elements.
var numFiltered = documents[0].count;
// Filter, sort and pagiante.
model.request.aggregate(aggregationPaginated)
.allowDiskUse(true)
.exec(
function(errFindP, documentsP) {
if (errFindP) {
// Errors.
res.status(503);
return res.json({
'success': false,
'response': 'err_pagination'
});
}
else {
return res.json({
'success': true,
'recordsTotal': totalCount,
'recordsFiltered': numFiltered,
'response': documentsP
});
}
});
}
});
});