Я использовал агрегацию для получения записей из mongodb.
$result = $collection->aggregate(array(
array('$match' => $document),
array('$group' => array('_id' => '$book_id', 'date' => array('$max' => '$book_viewed'), 'views' => array('$sum' => 1))),
array('$sort' => $sort),
array('$skip' => $skip),
array('$limit' => $limit),
));
Если я выполню этот запрос без ограничений, будет получено 10 записей. Но я хочу оставить ограничение равным 2. Итак, я хотел бы получить общее количество записей. Как я могу работать с агрегацией? Пожалуйста, посоветуй мне. Благодарность
Ответы:
Это один из наиболее часто задаваемых вопросов для получения результатов с разбивкой на страницы и общего количества результатов одновременно в одном запросе. Я не могу объяснить, что я чувствовал, когда наконец достиг этого LOL.
$result = $collection->aggregate(array( array('$match' => $document), array('$group' => array('_id' => '$book_id', 'date' => array('$max' => '$book_viewed'), 'views' => array('$sum' => 1))), array('$sort' => $sort), // get total, AND preserve the results array('$group' => array('_id' => null, 'total' => array( '$sum' => 1 ), 'results' => array( '$push' => '$$ROOT' ) ), // apply limit and offset array('$project' => array( 'total' => 1, 'results' => array( '$slice' => array( '$results', $skip, $length ) ) ) ) ))
Результат будет выглядеть примерно так:
[ { "_id": null, "total": ..., "results": [ {...}, {...}, {...}, ] } ]
источник
{ $group: { _id: null, count: { $sum:1 }, result: { $push: '$$ROOT' }}}
(вставить после,{$group:{}}
чтобы подсчитать общее количествоНачиная с версии 3.4 (я думаю), в MongoDB появился новый оператор конвейера агрегации с именем « фасет », который, по их собственным словам:
В данном конкретном случае это означает, что можно сделать что-то вроде этого:
$result = $collection->aggregate([ { ...execute queries, group, sort... }, { ...execute queries, group, sort... }, { ...execute queries, group, sort... }, $facet: { paginatedResults: [{ $skip: skipPage }, { $limit: perPage }], totalCount: [ { $count: 'count' } ] } ]);
Результат будет (например, 100 результатов):
[ { "paginatedResults":[{...},{...},{...}, ...], "totalCount":[{"count":100}] } ]
источник
$project
?Используйте это, чтобы найти общее количество в результирующей коллекции.
db.collection.aggregate( [ { $match : { score : { $gt : 70, $lte : 90 } } }, { $group: { _id: null, count: { $sum: 1 } } } ] );
источник
Вы можете использовать функцию toArray, а затем получить ее длину для общего количества записей.
источник
TypeError: Parent.aggregate(...).toArray is not a function
это ошибка, которую я дал с этим решением.Используйте этап конвейера агрегирования $ count, чтобы получить общее количество документов:
Запрос:
db.collection.aggregate( [ { $match: { ... } }, { $group: { ... } }, { $count: "totalCount" } ] )
Результат:
{ "totalCount" : Number of records (some integer value) }
источник
Я сделал это так:
db.collection.aggregate([ { $match : { score : { $gt : 70, $lte : 90 } } }, { $group: { _id: null, count: { $sum: 1 } } } ] ).map(function(record, index){ print(index); });
Агрегат вернет массив, поэтому просто зациклируйте его и получите окончательный индекс.
И другой способ сделать это:
var count = 0 ; db.collection.aggregate([ { $match : { score : { $gt : 70, $lte : 90 } } }, { $group: { _id: null, count: { $sum: 1 } } } ] ).map(function(record, index){ count++ }); print(count);
источник
var
ни объявление, ниmap
звонок. Достаточно первых трех строк вашего первого примера.Решение, предоставленное @Divergent, действительно работает, но, по моему опыту, лучше иметь 2 запроса:
Решение с нажатием $$ 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 }); } }); } }); });
источник
//const total_count = await User.find(query).countDocuments(); //const users = await User.find(query).skip(+offset).limit(+limit).sort({[sort]: order}).select('-password'); const result = await User.aggregate([ {$match : query}, {$sort: {[sort]:order}}, {$project: {password: 0, avatarData: 0, tokens: 0}}, {$facet:{ users: [{ $skip: +offset }, { $limit: +limit}], totalCount: [ { $count: 'count' } ] }} ]); console.log(JSON.stringify(result)); console.log(result[0]); return res.status(200).json({users: result[0].users, total_count: result[0].totalCount[0].count});
источник
Это может работать для нескольких условий соответствия
const query = [ { $facet: { cancelled: [ { $match: { orderStatus: 'Cancelled' } }, { $count: 'cancelled' } ], pending: [ { $match: { orderStatus: 'Pending' } }, { $count: 'pending' } ], total: [ { $match: { isActive: true } }, { $count: 'total' } ] } }, { $project: { cancelled: { $arrayElemAt: ['$cancelled.cancelled', 0] }, pending: { $arrayElemAt: ['$pending.pending', 0] }, total: { $arrayElemAt: ['$total.total', 0] } } } ] Order.aggregate(query, (error, findRes) => {})
источник
Мне нужен был абсолютный общий счет после применения агрегации. Это сработало для меня:
db.mycollection.aggregate([ { $group: { _id: { field1: "$field1", field2: "$field2" }, } }, { $group: { _id: null, count: { $sum: 1 } } } ])
Результат:
{ "_id" : null, "count" : 57.0 }
источник
Вот несколько способов получить общее количество записей при агрегировании MongoDB:
Использование
$count
:db.collection.aggregate([ // Other stages here { $count: "Total" } ])
Для получения 1000 записей это в среднем занимает 2 мс и является самым быстрым способом.
Использование
.toArray()
:Для получения 1000 записей требуется в среднем 18 мс.
Использование
.itcount()
:Для получения 1000 записей требуется в среднем 14 мс.
источник
Извините, но я думаю, вам нужно два запроса. Один для общего просмотра, а другой для сгруппированных записей.
Вы можете найти полезный этот ответ
источник
Если вы не хотите группироваться, используйте следующий метод:
db.collection.aggregate( [ { $match : { score : { $gt : 70, $lte : 90 } } }, { $count: 'count' } ] );
источник