mongodb에서 마지막 N 레코드를 얻는 방법?


523

문서화 된 곳을 찾을 수 없습니다. 기본적으로 find () 작업은 처음부터 레코드를 가져옵니다. mongodb에서 마지막 N 레코드를 어떻게 얻을 수 있습니까?

편집 : 또한 반환 된 결과를 최신이 아닌 최신 순서로 정렬하고 싶습니다.


7
@Haim, plase는 답변을 구체적으로 제시합니다. 웹 페이지의 어느 부분이 내 질문을 해결합니까?
Bin Chen

안녕하세요 @ BinChen, 최근에 같은 문제가 있습니다. 해결 되었습니까?
Hanton

답변:


736

질문을 이해하면 오름차순으로 정렬해야합니다.

"x"라는 ID 또는 날짜 필드가 있다고 가정하면 ...

.종류()


db.foo.find().sort({x:1});

1 오름차순으로 정렬 (오래된 최신까지) 것이다 -1 내림차순 정렬한다 (최신 가장한다.)

자동 생성 된 _id 필드 를 사용하는 경우 날짜가 포함되어 있으므로이를 사용하여 주문할 수 있습니다.

db.foo.find().sort({_id:1});

그러면 모든 문서가 가장 오래된 것부터 가장 오래된 것으로 되돌아갑니다.

자연 질서


위에서 언급 한 자연 질서를 사용할 수도 있습니다 ...

db.foo.find().sort({$natural:1});

다시, 원하는 순서에 따라 1 또는 -1을 사용하십시오 .

.limit () 사용


마지막으로 이런 종류의 열린 쿼리를 수행 할 때 제한을 추가하여 다음 중 하나를 수행하는 것이 좋습니다.

db.foo.find().sort({_id:1}).limit(50);

또는

db.foo.find().sort({$natural:1}).limit(50);

11
@MortezaM. 쿼리 순서가 혼동되어 있다고 확신합니다 ... sort ()는 처음이 아닌 마지막으로 실행되어야합니다 (SQL ORDER BY와 유사) .find ({}). skip (1) .limit ( 50) .sort ({ "date":-1})
Justin Jenkins

6
그것이 무엇이든간에, 함수 호출 순서는 최종 결과와 아무런 관련이 없어야합니다.
Morteza Milani

7
@MortezaM. 물론 순서가 중요합니다. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;순서없이 결과는 무엇입니까? 이 역순은 직관적이지 않다는 것에 동의합니다. 이것은 정상적인 OO 패러다임을 따라야하는 SQL이 아닙니다.
RickyA

37
그러나 순서는 중요하지 않습니다. 당신이해야 할 일은 그것을하지 않는 것을 시도하는 것입니다. 이 모든 것이 커서에서 호출되어 서버로 전달되므로 서버는 다른 의미가없는 것처럼 정렬 결과 (상위 N)를 제한합니다.
Asya Kamsky

9
문서에서 주문이 중요하지 않음을 확인합니다. link
JohnnyHK

120

최근부터 최근까지 추가 된 마지막 N 개의 레코드는이 쿼리에서 볼 수 있습니다.

db.collection.find().skip(db.collection.count() - N)

역순으로 원하는 경우 :

db.collection.find().sort({ $natural: -1 }).limit(N)

Mongo-Hacker 를 설치하면 다음 을 사용할 수도 있습니다.

db.collection.find().reverse().limit(N)

이 명령을 작성하는 데 항상 지치면 ~ / .mongorc.js에서 사용자 정의 함수를 작성할 수 있습니다. 예 :

function last(N) {
    return db.collection.find().skip(db.collection.count() - N);
}

그런 다음 mongo shell에서 다음을 입력하십시오. last(N)


1
db.collection.find().reverse().limit(1)오류가 발생합니다... has no method reverse
Catfish

@Catfish 당신이 맞아요, 그냥 reverse ()가 [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ) 에 의해 추가 된 것을 알았습니다 . 내 대답을 업데이트 할 것입니다. 감사.
Trasplazio Garzuglio

1
db.getCollection ( 'COLLECTION_NAME'). find (). skip (db.getCollection ( 'COLLECTION_NAME'). count ()-N) 나를 위해 잘 작동 :)
Spl2nky

이것은 Justin Jenkins의 답변이 아니라 질문에 대한 답변이어야합니다.
Jadiel de Armas

자연 질서에 의존 해서는 안됩니다 . 복제 세트를 사용하는 경우 (필요한 경우) 다른 노드에 동일한 문서가 디스크에서 다른 순서로 저장되어있을 수 있습니다.
빈스 Bowdren

14

마지막 N 개의 레코드를 얻으려면 아래 쿼리를 실행할 수 있습니다.

db.yourcollectionname.find({$query: {}, $orderby: {$natural : -1}}).limit(yournumber)

마지막 레코드를 하나만 원하는 경우 :

db.yourcollectionname.findOne({$query: {}, $orderby: {$natural : -1}})

참고 : $ natural 대신 컬렉션의 열 중 하나를 사용할 수 있습니다.


이것은 나를 위해 작동합니다 db.yourcollectionname.findOne ({$ query : {}, $ orderby : {$ natural : -1}}). 나는 마지막 마비가 답에서 빠졌다고 생각한다
Ajay

자연 질서에 의존 해서는 안됩니다 . 복제 세트를 사용하는 경우 (필요한 경우) 다른 노드에 동일한 문서가 디스크에서 다른 순서로 저장되어있을 수 있습니다.
빈스 Bowdren

6

, 을 사용 하여 건너 뛴 값에서 마지막 N 레코드 시작을 가져올 수 있습니다 sort().limit()skip()

db.collections.find().sort(key:value).limit(int value).skip(some int value);

6

이 방법을 시도해 볼 수 있습니다.

컬렉션의 총 레코드 수를

db.dbcollection.count() 

그런 다음 skip을 사용하십시오.

db.dbcollection.find().skip(db.dbcollection.count() - 1).pretty()

5

1
귀하의 답변에 감사드립니다, 그것은 가깝지만 최근에서 가장 최근에 주문한 레코드를 다시 작성하고 싶습니다. 가능합니까?
Bin Chen

자연 질서에 의존 해서는 안됩니다 . 복제 세트를 사용하는 경우 (필요한 경우) 다른 노드에 동일한 문서가 디스크에서 다른 순서로 저장되어있을 수 있습니다.
빈스 Bowdren

최신 레코드를 얻으려면 문서의 날짜 필드를 사용해야합니다.
빈스 Bowdren

5

컬렉션의 크기에 따라 "건너 뛰기"할 수 없습니다. 쿼리 조건을 고려하지 않기 때문입니다.

올바른 해결책은 원하는 엔드 포인트에서 정렬하고 결과 집합의 크기를 제한 한 다음 필요한 경우 결과 순서를 조정하는 것입니다.

실제 코드를 기반으로 한 예입니다.

var query = collection.find( { conditions } ).sort({$natural : -1}).limit(N);

query.exec(function(err, results) {
    if (err) { 
    }
    else if (results.length == 0) {
    }
    else {
        results.reverse(); // put the results into the desired order
        results.forEach(function(result) {
            // do something with each result
        });
    }
});

좋은 해결 방법! 그래도 쿼리 수준에서 동일한 작업을 수행 할 수 있다면 좋을 것입니다. 같은 것 var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
inwpitrust

4

@ 빈 첸,

컬렉션에서 문서 하위 집합의 최신 n 개 항목에 대해 집계를 사용할 수 있습니다. 다음은 그룹화가없는 단순화 된 예입니다 (이 경우 4 단계와 5 단계 사이에서 수행함).

"오름차순으로 정렬 된"timestamp "필드를 기준으로 최신 20 개의 항목을 반환합니다. 그런 다음 각 문서 _id, 타임 스탬프 및 whatever_field_you_want_to_show를 결과에 투영합니다.

var pipeline = [
        {
            "$match": { //stage 1: filter out a subset
                "first_field": "needs to have this value",
                "second_field": "needs to be this"
            }
        },
        {
            "$sort": { //stage 2: sort the remainder last-first
                "timestamp": -1
            }
        },
        {
            "$limit": 20 //stage 3: keep only 20 of the descending order subset
        },
        {
            "$sort": {
                "rt": 1 //stage 4: sort back to ascending order
            }
        },
        {
            "$project": { //stage 5: add any fields you want to show in your results
                "_id": 1,
                "timestamp" : 1,
                "whatever_field_you_want_to_show": 1
            }
        }
    ]

yourcollection.aggregate(pipeline, function resultCallBack(err, result) {
  // account for (err)
  // do something with (result)
}

결과는 다음과 같습니다.

{ 
    "_id" : ObjectId("5ac5b878a1deg18asdafb060"),
    "timestamp" : "2018-04-05T05:47:37.045Z",
    "whatever_field_you_want_to_show" : -3.46000003814697
}
{ 
    "_id" : ObjectId("5ac5b878a1de1adsweafb05f"),
    "timestamp" : "2018-04-05T05:47:38.187Z",
    "whatever_field_you_want_to_show" : -4.13000011444092
}

도움이 되었기를 바랍니다.


1
@ lauri108 감사합니다! 이 질문과 관련 질문에 대한 모든 답변 중에서 "LAST N DOCS를 얻는 방법"에 대한 유일한 효과적이고 신뢰할 수있는 솔루션입니다. 한 번의 쿼리로 수행 할 수있을만큼 간단합니다. 작업이 완료되었습니다.
randomsock

@randomsock 만약 당신이 그것을 좋아한다면, 그것을 투표 :)
lauri108

4

컬렉션의 크기에 따라 정렬, 건너 뛰기 등이 상당히 느려질 수 있습니다.

컬렉션을 일부 기준으로 색인화하면 성능이 향상됩니다. 그런 다음 min () 커서를 사용할 수 있습니다.

먼저, db.collectionName.setIndex( yourIndex ) "N last items"를 원하므로 오름차순 또는 내림차순을 사용할 수 있습니다. 내림차순으로 색인을 생성하는 경우 "first N items"를 얻는 것과 같습니다 .

그런 다음 컬렉션의 첫 번째 항목을 찾아 다음과 같은 검색에서 해당 인덱스 필드 값을 최소 기준으로 사용합니다.

db.collectionName.find().min(minCriteria).hint(yourIndex).limit(N)

다음은 min () 커서에 대한 참조입니다. https://docs.mongodb.com/manual/reference/method/cursor.min/


성능을 고려한 답변 만, 훌륭한 추가 :)
zardilior

이 답변이 주문을 보장합니까?
zardilior

예, 지수에 따라 보장됩니다
João Otero

1
분명히 당신은 min을 잊고 사용할 수 있습니다 : db.collectionName.find().hint(yourIndex).limit(N) 인덱스가 내림차순이면 N 최소값을 얻습니다.
haltux


0
db.collection.find().hint( { $natural : -1 } ).sort(field: 1/-1).limit(n)

mongoDB 설명서 에 따르면 :

{$ natural : 1}을 지정하여 쿼리가 전달 수집 스캔을 수행하도록 할 수 있습니다.

{$ natural : -1}을 지정하여 쿼리가 리버스 컬렉션 검색을 수행하도록 할 수도 있습니다.


0

$ slice 연산자를 사용 하여 배열 요소를 제한하십시오.

GeoLocation.find({},{name: 1, geolocation:{$slice: -5}})
    .then((result) => {
      res.json(result);
    })
    .catch((err) => {
      res.status(500).json({ success: false, msg: `Something went wrong. ${err}` });
});

지리적 위치는 마지막 5 개의 레코드를 얻는 데이터의 배열입니다.


-5

마지막 함수는 sort아니 어야합니다 limit.

예:

db.testcollection.find().limit(3).sort({timestamp:-1}); 

2
이것은 잘못된 것 같습니다. 왜 것입니다 sort후 수 limit?
Acumenus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.