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": [
{...},
{...},
{...},
]
}
]
답변
v.3.4 이후 (내 생각에) MongoDB에는 이제 ‘ facet ‘ 라는 새로운 집계 파이프 라인 연산자 가 있습니다.
동일한 입력 문서 세트의 단일 단계 내에서 여러 집계 파이프 라인을 처리합니다. 각 하위 파이프 라인에는 결과가 문서 배열로 저장되는 출력 문서에 자체 필드가 있습니다.
이 특별한 경우에는 다음과 같이 할 수 있습니다.
$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}]
}
]
답변
이를 사용하여 결과 수집에서 총 개수를 찾습니다.
db.collection.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );
답변
toArray 함수를 사용한 다음 총 레코드 수에 대한 길이를 가져올 수 있습니다.
db.CollectionName.aggregate([....]).toArray().length
답변
사용 $ 카운트 집계 파이프 라인 단계를 총 페이지 수를 얻을 수 :
쿼리 :
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);
답변
@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
});
}
});
}
});
});