MongoDB Aggregation : 총 레코드 수를 얻는 방법은 무엇입니까?
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 : { 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);
사용 $ 카운트 집계 파이프 라인 단계를 총 페이지 수를 얻을 수 :
쿼리 :
db.collection.aggregate(
[
{
$match: {
...
}
},
{
$group: {
...
}
},
{
$count: "totalCount"
}
]
)
결과:
{
"totalCount" : Number of records (some integer value)
}
@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});
참고URL : https://stackoverflow.com/questions/20348093/mongodb-aggregation-how-to-get-total-records-count
'code' 카테고리의 다른 글
스타일에 대한 Angular 2.0 바인딩 값 (0) | 2020.10.21 |
---|---|
Count 속성 대 Count () 메서드? (0) | 2020.10.21 |
플래시 메시지가 사라지지 않는 이유는 무엇입니까? (0) | 2020.10.20 |
MySQL에서 월 및 연도별로 그룹화 (0) | 2020.10.20 |
Java 인터페이스는 다중 상속을 어떻게 시뮬레이션합니까? (0) | 2020.10.20 |