MongoDB
 Computer >> コンピューター >  >> プログラミング >> MongoDB

MongoDBの$group操作でソートし、各グループの先頭ドキュメントのみを取得する方法

MongoDBの集計パイプラインでは、$sortでドキュメントを並べ替えた後に$group$firstを組み合わせることで、グループごとにソート結果の先頭1件だけを効率的に取得できます。本記事では、サンプルコレクションを作成しながら、その具体的な手順をわかりやすく解説します。

サンプルコレクションの作成

まず、insertOne()メソッドを使って、ドキュメントを含むコレクションを作成しましょう。

> db.demo576.insertOne({id:101,Name:"Chris",Marks:45}){
   "acknowledged" : true, "insertedId" : ObjectId("5e916c3b581e9acd78b427fa")
}
> db.demo576.insertOne({id:101,Name:"John",Marks:55}){
   "acknowledged" : true, "insertedId" : ObjectId("5e916c43581e9acd78b427fb")
}
> db.demo576.insertOne({id:101,Name:"John",Marks:65}){
   "acknowledged" : true, "insertedId" : ObjectId("5e916c47581e9acd78b427fc")
}
> db.demo576.insertOne({id:102,Name:"David",Marks:37}){
   "acknowledged" : true, "insertedId" : ObjectId("5e916c55581e9acd78b427fd")
}
> db.demo576.insertOne({id:102,Name:"David",Marks:75}){
   "acknowledged" : true, "insertedId" : ObjectId("5e916c5e581e9acd78b427fe")
}

find()メソッドですべてのドキュメントを確認

find()メソッドを使うと、コレクション内のすべてのドキュメントを表示できます。

> db.demo576.find();

上記のクエリを実行すると、次のような出力が得られます。

{ "_id" : ObjectId("5e916c3b581e9acd78b427fa"), "id" : 101, "Name" : "Chris", "Marks" : 45 }
{ "_id" : ObjectId("5e916c43581e9acd78b427fb"), "id" : 101, "Name" : "John", "Marks" : 55 }
{ "_id" : ObjectId("5e916c47581e9acd78b427fc"), "id" : 101, "Name" : "John", "Marks" : 65 }
{ "_id" : ObjectId("5e916c55581e9acd78b427fd"), "id" : 102, "Name" : "David", "Marks" : 37 }
{ "_id" : ObjectId("5e916c5e581e9acd78b427fe"), "id" : 102, "Name" : "David", "Marks" : 75 }

$sort・$group・$firstを組み合わせた集計クエリ

続いて、「$group」操作の中でソートを行い、各グループの先頭ドキュメントのみを取得するクエリを見ていきます。ポイントは次の3つのステージです。

  • $sort:Marksフィールドを昇順(1)に並べ替えます。
  • $group:idフィールドでグループ化し、$first演算子で$$ROOT(ドキュメント全体)の先頭1件を取得します。
  • $project:出力に必要なフィールドだけを整形して返します。
> var query = [
...    {
...       "$sort": { "Marks": 1 }
...    },
...    {
...       "$group": {
...          "_id": "$id",
...          "out": { "$first": "$$ROOT" }
...       }
...    },
...    {
...       "$project": {
...          "_id": "$out._id",
...          "id": "$out.id",
...          "Name": "$out.Name",
...          "MinMarks": "$out.Marks"
...       }
...    }
... ]
> db.demo576.aggregate(query);

このクエリを実行すると、次のような出力が得られます。

{ "_id" : ObjectId("5e916c3b581e9acd78b427fa"), "id" : 101, "Name" : "Chris", "MinMarks" : 45 }
{ "_id" : ObjectId("5e916c55581e9acd78b427fd"), "id" : 102, "Name" : "David", "MinMarks" : 37 }

結果のポイント

出力結果を見ると、idごとにMarksが最小のドキュメント(id:101ならChrisの45点、id:102ならDavidの37点)が1件ずつ取得できていることがわかります。このように$sort → $group → $firstの組み合わせは、「グループごとの最大値や最小値を持つレコードを丸ごと取り出したい」というケースで非常に便利なテクニックです。ランキングの上位者抽出や、各カテゴリの最新データ取得など、実務でも幅広く活用できます。

  1. MongoDBでIDを並べ替えてアイテムを逆順に取得する方法

    MongoDBでは、$naturalを使用するとドキュメントが自然順(natural order)で返されます。この順序を逆にしたい場合は、$natural:-1を指定します。サンプルコレクションの作成まず、ドキュメントを含むコレクションを作成しましょう。> db.demo710.insertOne({id:101,Name:"Robert"}); { "acknowledged" : true, "insertedId" : ObjectId("5ea83a855d33e20ed1097b7a&quo

  2. MongoDBの集計パイプラインで点数が最も少ない2つのドキュメントを取得する方法

    点数(Marks)の昇順に並べ替えたリストを取得するには $sort を使用します。さらに $limit: 2 を組み合わせることで、点数が最も少ない2件のドキュメントだけを表示できます。ここでは、実際に動作を確認できるよう、サンプル用のコレクションを作成していきましょう。1. サンプルコレクションの作成まずは insertOne() メソッドを使って、4件のドキュメントを登録します。> db.demo709.insertOne({Name:"John","Marks":75}); {    "acknowledged