MongoDB 범위 페이지 설정
레코드가 많은 MongoDB 컬렉션에서 skip()을 페이지 처리에 사용하는 것은 느리고 권장되지 않는 것으로 알려져 있습니다.
범위 페이지 번호부여(>_id 컴파션 기준)를 사용할 수 있습니다.
db.items.find({_id: {$gt: ObjectId('4f4a3ba2751e88780b000000')}});
프리버튼과 다음 버튼을 표시하는 것은 좋지만, 실제 페이지 번호 1을 표시하는 경우는 실장이 쉽지 않습니다.5 6 7 ... 124 - 각 페이지의 선두에 있는 「_id」를 미리 등록해 둘 필요가 있습니다.
두 가지 질문이 있습니다.
1) 언제부터 고민하면 될까요?skip()의 속도가 현저하게 느려진 "레코드 수가 너무 많은" 경우? 1,000? 1,000?
2) 범위 페이지 번호를 사용하여 실제 페이지 번호와 링크를 표시하는 가장 좋은 방법은 무엇입니까?
좋은 질문입니다!
"몇 개가 너무 많습니까?" 물론 데이터 크기와 성능 요건에 따라 달라집니다.저는 개인적으로 500~1000개 이상의 레코드를 건너뛸 때 불편함을 느낍니다.
실제 답은 사용자의 요구 사항에 따라 달라집니다.현대 사이트의 기능은 다음과 같습니다(또는 적어도 일부).
첫 번째 네비게이션바는 다음과 같습니다.
1 2 3 ... 457
최종 페이지 번호는 총 레코드 수와 페이지 크기에서 얻을 수 있습니다.3페이지로 넘어갑시다.그것은 첫 번째 음반에서 약간의 건너뛰기를 수반할 것이다.결과가 도착하면 3페이지의 첫 번째 레코드의 ID를 알게 됩니다.
1 2 3 4 5 ... 457
조금 더 건너뛰고 5페이지로 넘어갑시다.
1 ... 3 4 5 6 7 ... 457
무슨 말인지 아시겠죠?각 시점에서 첫 페이지, 마지막 페이지 및 현재 페이지가 표시되고 현재 페이지에서 앞뒤로 두 페이지가 표시됩니다.
쿼리
var current_id; // id of first record on current page.
// go to page current+N
db.collection.find({_id: {$gte: current_id}}).
skip(N * page_size).
limit(page_size).
sort({_id: 1});
// go to page current-N
// note that due to the nature of skipping back,
// this query will get you records in reverse order
// (last records on the page being first in the resultset)
// You should reverse them in the app.
db.collection.find({_id: {$lt: current_id}}).
skip((N-1)*page_size).
limit(page_size).
sort({_id: -1});
표시되는 결과 집합을 구성하기 위해 사용하는 쿼리에 따라 크게 달라지기 때문에 일반적인 답변을 드리기는 어렵습니다.인덱스만 사용하여 결과를 찾을 수 있고 인덱스 순서로 표시되는 경우 db.dataset.find(.limit().skip()는 다수의 건너뛰기를 수행해도 양호한 성능을 발휘할 수 있습니다.이것이 코드화하는 가장 쉬운 방법일 것입니다.그러나 이 경우에도 페이지 번호를 캐시하고 인덱스 값에 연결할 수 있으면 예를 들어 71페이지를 보려는 두 번째 및 세 번째 사용자가 더 빨리 페이지 번호를 볼 수 있습니다.
다른 사용자가 데이터를 페이징하는 동안 문서가 추가 및 삭제되는 매우 동적인 데이터 집합에서는 이러한 캐싱이 빠르게 구식이 되고 제한 및 건너뛰기 방법이 좋은 결과를 제공할 수 있을 정도로 신뢰할 수 있는 유일한 방법이 될 수 있습니다.
최근 "First Name"과 같이 고유하지 않은 필드를 사용하다가 요청에 페이지 번호를 매기려고 할 때 동일한 문제가 발생합니다.이 쿼리의 아이디어는 skip()을 사용하지 않고 고유하지 않은 필드에 페이지 매김을 구현할 수 있도록 하는 것입니다.
여기서의 주된 문제는, 「FirstName(이름)」이 아닌 필드를 쿼리할 수 있는 것입니다.이는 다음과 같은 상황이 발생하기 때문입니다.
- $gt: {"FirstName": "Carlos"} -> 이름이 "Carlos"인 모든 레코드는 건너뜁니다.
- $gte: {"FirstName": "Carlos"} ->는 항상 같은 데이터 세트를 반환합니다.
그래서 제가 생각해낸 솔루션은 쿼리의 $match 부분을 고유 검색으로 만들기 위해 대상 검색 필드와 보조 필드를 결합하여 고유하게 만드는 것이었습니다.
오름차순:
db.customers.aggregate([
{$match: { $or: [ {$and: [{'FirstName': 'Carlos'}, {'_id': {$gt: ObjectId("some-object-id")}}]}, {'FirstName': {$gt: 'Carlos'}}]}},
{$sort: {'FirstName': 1, '_id': 1}},
{$limit: 10}
])
내림차순:
db.customers.aggregate([
{$match: { $or: [ {$and: [{'FirstName': 'Carlos'}, {'_id': {$gt: ObjectId("some-object-id")}}]}, {'FirstName': {$lt: 'Carlos'}}]}},
{$sort: {'FirstName': -1, '_id': 1}},
{$limit: 10}
])
이 쿼리의 $match 부분은 기본적으로 if 문처럼 동작합니다.firstName이 "Carlos"인 경우 firstName이 "Carlos"와 같지 않은 경우 이 ID보다 커야 하며, FirstName이 "Carlos"보다 커야 합니다.
유일한 문제는 특정 페이지 번호로 네비게이트할 수 없다는 것입니다(아마도 코드 조작으로 할 수 있을 것입니다).다만, 고유하지 않은 필드의 페이지 번호 할당에 관한 문제는, 스킵을 사용하지 않아도 해결됩니다.스킵은, 어느 데이터 세트의 마지막에 액세스 할 때에 대량의 메모리와 처리 능력을 소비합니다.
언급URL : https://stackoverflow.com/questions/9703319/mongodb-ranged-pagination
'programing' 카테고리의 다른 글
| 콘솔에서 리액트 요소의 소품 및 상태를 검사하려면 어떻게 해야 합니까? (0) | 2023.04.02 |
|---|---|
| AngularJS - ng-if 체크 문자열 빈 값 (0) | 2023.04.02 |
| 간격 데이터 유형에서 총 초수 추출 (0) | 2023.04.02 |
| Excel interop 객체를 적절하게 정리하려면 어떻게 해야 하나요? (0) | 2023.04.02 |
| React에서 Link 컴포넌트를 사용할 때 jsx-a11y/anchor-is-valid를 수정하려면 어떻게 해야 합니까? (0) | 2023.04.02 |