MongoDB 원거리 페이지 매김
레코드가 많은 MongoDB 컬렉션에서 페이지 매김을 위해 skip ()을 사용하는 것은 느리고 권장되지 않는다고합니다.
범위 지정 페이지 매김 (> _id 비교 기준)을 사용할 수 있습니다.
db.items.find({_id: {$gt: ObjectId('4f4a3ba2751e88780b000000')}});
prev를 표시하는데 좋습니다. & 다음 버튼-하지만 실제 페이지 번호 1 ... 5 6 7 ... 124를 표시하려는 경우 구현하기가 쉽지 않습니다. 각 페이지가 시작되는 "_id"를 미리 계산해야합니다.
그래서 두 가지 질문이 있습니다.
1) 언제부터 걱정해야하나요? skip ()에 대해 눈에 띄게 느려지는 "너무 많은 레코드"가있을 때? 1,000? 1000000?
2) 범위 지정 페이지 매김을 사용할 때 실제 페이지 번호가있는 링크를 표시하는 가장 좋은 방법은 무엇입니까?
좋은 질문!
"너무 많아요?" -물론 데이터 크기와 성능 요구 사항에 따라 다릅니다. 개인적으로 500 ~ 1000 개 이상의 레코드를 건너 뛰면 불편 함을 느낍니다.
실제 대답은 요구 사항에 따라 다릅니다. 다음은 현대 사이트가 수행하는 작업 (또는 적어도 일부)입니다.
먼저 navbar는 다음과 같습니다.
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 페이지를보고자하는 두 번째와 세 번째 사람을 위해 더 빠르게 만들 수 있습니다.
다른 사람이 데이터를 페이징하는 동안 문서가 추가 및 제거되는 매우 동적 인 데이터 세트에서 이러한 캐싱은 빠르게 오래되고 제한 및 건너 뛰기 방법이 좋은 결과를 제공 할 수있을만큼 신뢰할 수있는 유일한 방법 일 수 있습니다.
최근에 "FirstName"과 같이 고유하지 않은 필드를 사용하는 동안 요청을 페이지 매김하려고 할 때 동일한 문제가 발생했습니다. 이 쿼리의 아이디어는 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}
])
The $match part of this query is basically behaving as an if statement: if firstName is "Carlos" then it needs to also be greater than this id if firstName is not equal to "Carlos" then it needs to be greater than "Carlos"
Only problem is that you cannot navigate to an specific page number (it can probably be done with some code manipulation) but other than it solved my problem with pagination for non-unique fields without having to use skip which eats a lot of memory and processing power when getting to the end of whatever dataset you are querying for.
참고URL : https://stackoverflow.com/questions/9703319/mongodb-ranged-pagination
'program tip' 카테고리의 다른 글
숫자 리터럴의 ULL 접미사 (0) | 2020.11.15 |
---|---|
내부 클래스가 private final 메서드를 재정의 할 수있는 이유는 무엇입니까? (0) | 2020.11.15 |
Python 팬더의 데이터 프레임에서 matplotlib 산점도 만들기 (0) | 2020.11.15 |
Joda-Time DateTime을 java.util.Date로 또는 그 반대로 변환하는 방법은 무엇입니까? (0) | 2020.11.15 |
동적 데이터베이스 스키마 (0) | 2020.11.15 |