[mongodb] 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: {
        ...
      }
    },
    {
      $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에서 제공하는 솔루션은 작동하지만 내 경험상 두 가지 쿼리를 갖는 것이 좋습니다.

  1. 먼저 필터링 한 다음 ID별로 그룹화하여 필터링 된 요소 수를 가져옵니다. 여기에서 필터링하지 마십시오. 불필요합니다.
  2. 필터링, 정렬 및 페이지를 매기는 두 번째 쿼리입니다.

$$ 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
            });
          }
      });
    }
  });
});