我已经使用聚合从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。因此,我想获取总记录数。 如何进行汇总? 请给我建议。 谢谢
如果只有2,结果将是什么样?
这是在单个查询中同时获得分页结果和结果总数的最常见问题之一。我无法解释当我最终实现它时的感受。
$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": [
{...},
{...},
{...},
]
}
]
有关此文档:docs.mongodb.com/v3.2/reference/operator/aggregation/group/ ...请注意,使用这种方法,整个非分页结果集必须适合16MB。
这是纯金!我一直在努力使这项工作顺利进行。
谢了,兄弟们 !我只需要{ $group: { _id: null, count: { $sum:1 }, result: { $push: $$ROOT }}}(在{$group:{}}之后插入即可进行总计数查找。
您如何将限制应用于结果集?结果现在是一个嵌套数组
@valen您可以看到代码的最后一行" results => array($ slice => array($ results,$ skip,$ length))"在这里您可以应用限制并跳过参数
很好的答案!
我的生活已经完成,我可以幸福地死
非常有帮助,谢谢! ??
从v.3.4(我认为)开始,MongoDB现在有了一个名为" facet"的新聚合管道运算符,用自己的话说:
Processes multiple aggregation pipelines within a single stage on the same set of input documents. Each sub-pipeline has its own field in the output document where its results are stored as an array of documents.
在这种特殊情况下,这意味着可以执行以下操作:
$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}]
}
]
从3.4开始,这很好用,应该是公认的答案
要将如此多的结果转换为简单的两个字段对象,我需要另一个$project吗?
现在,这必须是公认的答案。像魅力一样运作。
这应该是今天公认的答案。但是,在与$ facet一起使用分页时,我发现了性能问题。另一个获得投票赞成的答案也有$ slice的性能问题。我发现最好在管道中跳过$ limit和$ limit并单独进行计数。我针对相当大的数据集进行了测试。
使用它来查找集合中的总数。
db.collection.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );
谢谢。但是,我在编码中使用了"视图"来获取相应组计数的计数(即,组1 => 2个记录,组3 => 5个记录,依此类推)。我想获取记录数(即总计:120条记录)。希望你理解..
您可以使用toArray函数,然后获取其长度以记录总数。
db.CollectionName.aggregate([....]).toArray().length
不建议用于性能...如果您的数据库很大。
尽管这可能无法作为"合适的"解决方案,但它可以帮助我调试某些内容-即使它不是100%的解决方案,它也可以工作。
这不适用于海量数据
这不是真正的解决方案。
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调用。您的第一个示例的前3行就足够了。
@Divergent提供的解决方案确实有效,但是以我的经验,最好有两个查询:
首先进行过滤,然后按ID分组以获取过滤元素的数量。不要在这里过滤,这是不必要的。
第二个查询,用于过滤,排序和分页。
推送$$ ROOT并使用$ slice的解决方案在大型集合中遇到了16MB的文档内存限制。同样,对于大型集合,两个查询一起运行似乎比使用$$ 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 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) => {})
//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});
通常最好的做法是将解释性文字与代码答案一起包括在内。
抱歉,但是我认为您需要两个查询。一个用于总视图,另一个用于分组记录。
您可以找到有用的答案
谢谢..我这样认为..但是,聚合没有选择.. :(
我遇到了类似的情况。没有答案,只能进行2个查询。 :( stackoverflow.com/questions/20113731/