かなり放置していましたが更新します。以前の記事はMongoDB3.4でして、現在は3.6を利用しています。今回の記事はバージョンの差異による問題は無いかと思います。
一覧にcountを出したい
PHPだとMySQL使ってましたが、1対多のテーブル構造でGroupByからのCountで件数を表示していました。Mongoでも似たことをやりたかったのですが、調べるのに苦労したので備忘としてメモしておきます。
タイトル | 質問 | 回答数 |
---|---|---|
ほげ | ほげほげ | 2 |
ふが | ふがふが | 5 |
ぬが | ぬがぬが | 0 |
こんな表を作りたい時のクエリです。
データ構造は例えば以下のパターンで考える
課題コレクション(kadais)
no(課題No=オブジェクトIDでも良い)
title(課題のタイトル)
question(課題の問題)
回答コレクション(kaitous)
kadai_no(回答の対象になった課題のNo)
answer(問題に対する回答)
データの入れ方等は本筋ではないので割愛
※ちなみにRobo 3T使ってます。
db.getCollection('kadais').insert([
{ 'no': 1, 'title': 'ほげ', 'question': 'ほげほげ' },
{ 'no': 2, 'title': 'ふが', 'question': 'ふがふが' },
{ 'no': 3, 'title': 'ぬが', 'question': 'ぬがぬが' },
]);
db.getCollection('kaitous').insert([
{ 'kadai_no': 1, 'answer': 'あ' }, { 'kadai_no': 1, 'answer': 'い' },
{ 'kadai_no': 2, 'answer': 'う' }, { 'kadai_no': 2, 'answer': 'え' }, { 'kadai_no': 2, 'answer': 'お' }, { 'kadai_no': 2, 'answer': 'か' },
]);
そしてSQLで言うところのJoinをして$sizeを使う
db.getCollection('kadais').aggregate([
{
"$lookup": {
"from": "kaitous",
"localField": "no",
"foreignField": "kadai_no",
"as": "kaitous"
}
},
{
"$project": {
"no": "$no",
"title": "$title",
"question": "$question",
"count": { "$size": "$kaitous" },
}
}
])
これで欲しかったものが取得できる。
ちょっと捻って正解数を出したいなって時
※簡略化のため、課題の問題に関係なくanswerが「あ」のものを正解とします。
db.getCollection('kadais').aggregate([
{
"$lookup": {
"from": "kaitous",
"localField": "no",
"foreignField": "kadai_no",
"as": "kaitous"
}
},
{
"$unwind": {
"path": "$kaitous",
"preserveNullAndEmptyArrays": true
}
},
{
"$project": {
"no": "$no",
"title": "$title",
"question": "$question",
"seikai": {
"$size": {
"$filter": {
"input": ["$kaitous"],
"as": "kaitou",
"cond": { "$eq": [ "$$kaitou.answer", "あ" ] }
}
}
}
}
},
{
"$group": {
"_id": {
"_id": "$_id",
"no": "$no",
"title": "$title",
"question": "$question",
},
"seikai": {
"$sum": "$seikai"
}
}
},
{
"$project": {
"no": "$_id.no",
"title": "$_id.title",
"question": "$_id.question",
"seikai": "$seikai",
}
}
])
こんな感じ
unwindに「"preserveNullAndEmptyArrays": true」を付けるとOuterJoin的なものになります。
デフォルトはInnerJoin的なものになってます。
あとは、filterつかってカウントの和を求めて正解数としています。
$cond~ifとかで何とかする手もありそうです。
最適解かは別として、使い方のメモ的な位置付けとしてご理解ください。
おわりに
如何でしょうか。Aggregateは色々出来すぎて探すのが大変でした。また時間を見つけて投稿出来れば思っています。間違え等あればご指摘をお願い致します。