2015-01-23 3 views
3

skip이 많은 메모리를 소비하기 시작하여 데이터가 커지면 skip을 사용하여 페이지 매김을 구현하는 것은 나쁜 습관임을 알고 있습니다. - 나는 몽고에 새로 온 사람이 매우 last_idmongodb의 페이지 매김 구현

+1

http://docs.mongodb.org/manual/reference/operator/query/gt/ – Disposer

+0

감사합니다. 그러나 last_id를 어떻게 얻어야하는지 알 수 없습니다. 그 점들 대신에 어떤 코드를 사용해야합니까 : 'last_id = ...'? – Jacobian

답변

10
을 얻을 수있는 가장 좋은 방법이 무엇인지 모르는

//Page 1 
db.users.find().limit(pageSize); 
//Find the id of the last document in this page 
last_id = ... 

//Page 2 
users = db.users.find({'_id'> last_id}). limit(10); 

문제는이 문제를 극복하는 한 가지 방법은 _id 필드에 의해 자연 순서를 사용하는 것입니다

당신이 말하는 개념은 "forward paging"이라고 부를 수 있습니다. 좋은 이유는 .skip().limit() 수식어를 사용하는 것과 달리 이전 페이지로 "돌아갈"수 없거나 특정 페이지로 건너 뛰는 데 사용할 수 없습니다. 적어도 "본"페이지 또는 "발견 된"페이지를 저장하기위한 많은 노력이 필요하지 않기 때문에 "페이지에 대한 링크"페이징 유형이 원하는대로라면 .skip().limit() 접근법을 고수하는 것이 가장 좋습니다. 성능 단점. 3 개 항목의 한계 첫 페이지입니다 물론

db.junk.find().limit(3) 

{ "_id" : ObjectId("54c03f0c2f63310180151877"), "a" : 1, "b" : 1 } 
{ "_id" : ObjectId("54c03f0c2f63310180151878"), "a" : 4, "b" : 4 } 
{ "_id" : ObjectId("54c03f0c2f63310180151879"), "a" : 10, "b" : 10 } 

: 그것은 단지 "앞으로 이동"에 당신에게 가능한 옵션 인 경우

는 여기에 기본 개념이다.

var lastSeen = null; 
var cursor = db.junk.find().limit(3); 

while (cursor.hasNext()) { 
    var doc = cursor.next(); 
    printjson(doc); 
    if (!cursor.hasNext()) 
    lastSeen = doc._id; 
} 

있도록 반복 커서와 무언가를하고, 커서의 마지막 항목에 도달 한 것은 사실 때 본 _idlastSeen 값을 저장 : 코드가 커서를 반복와 지금을 고려

을 이후의 반복에서
ObjectId("54c03f0c2f63310180151879") 

당신은 단지 먹이를 당신이 쿼리에 (세션 또는 무엇이든) 유지 _id 값 :

var cursor = db.junk.find({ "_id": { "$gt": lastSeen } }).limit(3); 

while (cursor.hasNext()) { 
    var doc = cursor.next(); 
    printjson(doc); 
    if (!cursor.hasNext()) 
    lastSeen = doc._id; 
} 

{ "_id" : ObjectId("54c03f0c2f6331018015187a"), "a" : 1, "b" : 1 } 
{ "_id" : ObjectId("54c03f0c2f6331018015187b"), "a" : 6, "b" : 6 } 
{ "_id" : ObjectId("54c03f0c2f6331018015187c"), "a" : 7, "b" : 7 } 

그리고 더 이상 결과를 얻을 수 없을 때까지 과정이 계속 반복됩니다.

자연 순서에 대한 기본 과정은 _id입니다. 뭔가 다른 경우에는 좀 더 복잡해집니다. 다음 고려 :

{ "_id": 4, "rank": 3 } 
{ "_id": 8, "rank": 3 } 
{ "_id": 1, "rank": 3 }  
{ "_id": 3, "rank": 2 } 

은 당신이 기본적으로 알아야 할 것은 당신이 "이미 본"그 결과를 제외 한 것입니다 다음 계급으로 분류 두 페이지에 그 분할. 당신이 lastSeen "순위"점수 작거나 같아야 할 다음 반복에

var lastSeen = null; 
var seenIds = []; 
var cursor = db.junk.find().sort({ "rank": -1 }).limit(2); 

while (cursor.hasNext()) { 
    var doc = cursor.next(); 
    printjson(doc); 
    if (lastSeen != null && doc.rank != lastSeen) 
     seenIds = []; 
    seenIds.push(doc._id); 
    if (!cursor.hasNext() || lastSeen == null) 
    lastSeen = doc.rank; 
} 

{ "_id": 4, "rank": 3 } 
{ "_id": 8, "rank": 3 } 

, 또한 그 이미 본 문서를 제외한 : 그래서 첫 번째 페이지를 찾고 있습니다. 당신은 $nin 연산자를 사용하여이 작업을 수행 :

var cursor = db.junk.find(
    { "_id": { "$nin": seenIds }, "rank": "$lte": lastSeen } 
).sort({ "rank": -1 }).limit(2); 

while (cursor.hasNext()) { 
    var doc = cursor.next(); 
    printjson(doc); 
    if (lastSeen != null && doc.rank != lastSeen) 
     seenIds = []; 
    seenIds.push(doc._id); 
    if (!cursor.hasNext() || lastSeen == null) 
    lastSeen = doc.rank; 
} 

{ "_id": 1, "rank": 3 }  
{ "_id": 3, "rank": 2 } 

얼마나 많은 "seenIds"당신은 실제로에 길게 그 값이 변경 될 곳 결과가 얼마나 "세분화"에 따라 달라집니다. 이 경우 현재 "순위"점수가 lastSeen 값과 같지 않은지 확인하고 현재 seenIds 콘텐츠를 삭제하여 콘텐츠가 너무 커지지 않도록 할 수 있습니다.

연습 및 학습을위한 "순방향 호출"의 기본 개념입니다.

+0

환상적입니다! – Jacobian

+0

@ Neil-Lunn, 완전하고 좋은 설명. 나는 당신에 대해 무언가를 발견했습니다. 잠을 자지 않은 것 같습니다. (농담 해) 항상 온라인에있는 것을 보았습니다.) – Disposer

+1

@Disposer Mobile App 및 로봇. 기계의 부상. –

관련 문제