mongodbの最後のNレコードを取得するにはどうすればよいですか?


523

これが記載されている場所はどこにもありません。デフォルトでは、find()操作はレコードを最初から取得します。mongodbの最後のNレコードを取得するにはどうすればよいですか?

編集:また、返された結果を新しいものから新しいものへと並べ替えたいが、逆ではない。


7
@ハイム、答えを具体的に説明してください。Webページのどの部分が私の質問を解決しますか?
Bin Chen

こんにちは@BinChen、私は最近同じ問題があります、それは解決されますか?
ハントン2015

回答:


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})
ジャスティンジェンキンス

6
それが何であれ、関数を呼び出す順序は最終結果とは関係ありません。
Morteza Milani

7
@MortezaM。もちろん、順序は重要です。item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;順序がなければ、結果はどうなるでしょうか??? この逆の順序は直感的ではないことに同意します。これはSQLではなく、通常のOOパラダイムに従う必要があります。
RickyA 2013

38
しかし、順序は関係ありません。あなたがしなければならないすべてはそれがそうでないことを確認するためにそれを試してみることです。これらはすべてカーソルで呼び出されてサーバーに渡されるため、サーバーは他の何も意味をなさないようにソートの結果(上位N)を制限します。
Asya Kamsky 2013年

10
文書は順序が問題ではないことを確認します:リンク
JohnnyHK 2013

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シェルから次のように入力します last(N)


1
db.collection.find().reverse().limit(1)エラーが表示されます... has no method reverse
ナマズ

@Catfishが正しい、reverse()が[Mongo-Hacker](tylerbrock.github.com/mongo-hacker)によって追加されたことに気付いたので、答えを更新します。ありがとう。
Trasplazio Garzuglio 2014年

1
db.getCollection( 'COLLECTION_NAME')。find()。skip(db.getCollection( 'COLLECTION_NAME')。count()-N)は、私にとって非常に効果的です:)
Spl2nky

これは質問に対する答えであり、Justin Jenkinsによる答えではありません。
Jadiel de Armas

自然な秩序に依存すべきではありません。レプリカセットを使用している場合(使用する必要があります)、異なるノードが同じドキュメントを異なる順序でディスクに格納している可能性があります。
Vince Bowdren 2017

14

最後のNレコードを取得するには、クエリの下で実行できます。

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

最後のレコードが1つだけ必要な場合:

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

注:$ naturalの代わりに、コレクションの列の1つを使用できます。


これは私のために動作しますdb.yourcollectionname.findOne({$ query:{}、$ orderby:{$ natural:-1}})。私は最後のパラセネシスが答えに欠けていると思います
アジャイ

自然な秩序に依存すべきではありません。レプリカセットを使用している場合(使用する必要があります)、異なるノードが同じドキュメントを異なる順序でディスクに格納している可能性があります。
Vince Bowdren 2017

6

あなたが使用することができsort()limit()skip()任意のスキップされた値から最後のNレコードの開始を取得します

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

6

あなたはこの方法を試すことができます:

コレクション内のレコードの総数を取得するには

db.dbcollection.count() 

次に、スキップを使用します:

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

5

1
あなたのanwserをありがとう、それは近いですが、新しいものから新しいものの順に並べられたレコードを再取得したいのですが、可能ですか?
Bin Chen

自然な秩序に依存すべきではありません。レプリカセットを使用している場合(使用する必要があります)、異なるノードが同じドキュメントを異なる順序でディスクに格納している可能性があります。
Vince Bowdren 2017

最新のレコードを取得する場合は、ドキュメントの日付フィールドを使用する必要があります。
Vince Bowdren 2017

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 2015年

4

@ bin-chen、

コレクション内のドキュメントのサブセットの最新のnエントリの集計を使用できます。以下は、グループ化を行わない簡単な例です(この場合は、ステージ4と5の間で行います)。

これは、昇順でソートされた(「タイムスタンプ」と呼ばれるフィールドに基づく)最新の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を取得する方法」に対する唯一の有効で信頼できるソリューションです。また、1つのクエリで実行できるほど単純です。仕事が終わりました。
randomsock

@randomsock気に入った場合は投票してください:)
lauri108

4

コレクションのサイズによっては、ソート、スキップなどがかなり遅くなる場合があります。

コレクションをいくつかの基準でインデックス化すると、パフォーマンスが向上します。そして、あなたはmin()カーソルを使うことができます:

まず、コレクションにインデックスを付けます。db.collectionName.setIndex( yourIndex ) 昇順または降順を使用できます。これは、常に「最後のN個のアイテム」が必要なため便利です。降順でインデックス付けすると、「最初のN個のアイテム」を取得するのと同じになります。 。

次に、コレクションの最初のアイテムを見つけ、そのインデックスフィールド値を次のような検索の最小基準として使用します。

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

これがmin()カーソルのリファレンスです:https : //docs.mongodb.com/manual/reference/method/cursor.min/


パフォーマンスを考慮に入れた唯一の回答、すばらしい追加:)
zardilior

この回答は順序を保証しますか?
zardilior

はい、それはあなたのインデックスに基づいて、保証
ジョアン・オテロ

1
どうやら、あなたは単に分を忘れて使用することができます: 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 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.