[mongodb] 몽구스 제한 / 오프셋 및 개수 쿼리

쿼리 성능에 대한 약간의 이상한 점 … 총 문서 수를 수행하는 쿼리를 실행하고 제한 및 오프셋 가능한 결과 집합을 반환 할 수도 있습니다.

그래서 총 57 개의 문서가 있고 사용자는 10 개의 문서를 20으로 오프셋하기를 원합니다.

이 작업을 수행하는 두 가지 방법을 생각할 수 있습니다. 먼저 57 개 문서 (배열로 반환 됨)를 모두 쿼리 한 다음 array.slice를 사용하여 원하는 문서를 반환합니다. 두 번째 옵션은 mongo의 기본 ‘count’메소드를 사용하여 두 번째 쿼리를 실행 한 다음 mongo의 기본 $ limit 및 $ skip 집계자를 사용하여 두 번째 쿼리를 실행하는 것입니다.

어느 것이 더 잘 확장 될 것이라고 생각하십니까? 모든 것을 하나의 쿼리로 수행하거나 두 개의 개별 쿼리를 실행합니까?

편집하다:

// 1 query
var limit = 10;
var offset = 20;

Animals.find({}, function (err, animals) {
    if (err) {
        return next(err);
    }

    res.send({count: animals.length, animals: animals.slice(offset, limit + offset)});
});


// 2 queries
Animals.find({}, {limit:10, skip:20} function (err, animals) {
    if (err) {
        return next(err);
    }

    Animals.count({}, function (err, count) {
        if (err) {
            return next(err);
        }

        res.send({count: count, animals: animals});
    });
});



답변

두 가지 쿼리를 사용하는 것이 좋습니다.

  1. db.collection.count()총 항목 수를 반환합니다. 이 값은 Mongo의 어딘가에 저장되며 계산되지 않습니다.

  2. db.collection.find().skip(20).limit(10)여기에서는 일부 필드별로 정렬을 사용할 수 있다고 가정하므로이 필드에 색인을 추가하는 것을 잊지 마십시오. 이 쿼리도 빠릅니다.

모든 항목을 쿼리하지 않고 건너 뛰고 가져가는 것보다 나중에 빅 데이터가 있으면 데이터 전송 및 처리에 문제가 생길 수 있다고 생각합니다.


답변

2 개의 별도 쿼리를 사용하는 대신 aggregate()단일 쿼리에서 사용할 수 있습니다 .

집계 “$ facet” 는 더 빨리 가져올 수 있으며 총 개수데이터 건너 뛰기 및 제한

    db.collection.aggregate([

      //{$sort: {...}}

      //{$match:{...}}

      {$facet:{

        "stage1" : [ {"$group": {_id:null, count:{$sum:1}}} ],

        "stage2" : [ { "$skip": 0}, {"$limit": 2} ]

      }},

     {$unwind: "$stage1"},

      //output projection
     {$project:{
        count: "$stage1.count",
        data: "$stage2"
     }}

 ]);

다음과 같이 출력 :-

[{
     count: 50,
     data: [
        {...},
        {...}
      ]
 }]

또한 https://docs.mongodb.com/manual/reference/operator/aggregation/facet/를 살펴보십시오.


답변

이 문제를 직접 해결 한 후 user854301의 답변을 기반으로 작성하고 싶습니다.

Mongoose ^ 4.13.8 toConstructor()필터가 적용될 때 쿼리를 여러 번 작성하지 않도록 하는 함수를 사용할 수있었습니다 . 이 기능은 이전 버전에서도 사용할 수 있다는 것을 알고 있지만이를 확인하려면 Mongoose 문서를 확인해야합니다.

다음은 Bluebird promise를 사용합니다.

let schema = Query.find({ name: 'bloggs', age: { $gt: 30 } });

// save the query as a 'template'
let query = schema.toConstructor();

return Promise.join(
    schema.count().exec(),
    query().limit(limit).skip(skip).exec(),

    function (total, data) {
        return { data: data, total: total }
    }
);

이제 개수 쿼리는 일치하는 총 레코드를 반환하고 반환 된 데이터는 총 레코드의 하위 집합이됩니다.

쿼리를 구성하는 query () 주변 의 ()에 유의하십시오 .


답변

이 모든 작업을 수행 할 라이브러리가 있습니다. mongoose-paginate-v2를 확인하세요.


답변

db.collection_name.aggregate([
    { '$match'    : { } },
    { '$sort'     : { '_id' : -1 } },
    { '$facet'    : {
        metadata: [ { $count: "total" } ],
        data: [ { $skip: 1 }, { $limit: 10 },{ '$project' : {"_id":0} } ] // add projection here wish you re-shape the docs
    } }
] )

총 개수를 찾기 위해 두 개의 쿼리를 사용하는 대신 일치하는 레코드를 건너 뜁니다.
$ facet은 가장 좋고 최적화 된 방법입니다.

  1. 기록과 일치
  2. total_count 찾기
  3. 기록을 건너 뛰다
  4. 또한 쿼리의 필요에 따라 데이터를 재구성 할 수도 있습니다.


답변