1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MongoDB一覧取得で閲覧数とかのカウントを取りたい時

Posted at

 かなり放置していましたが更新します。以前の記事は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は色々出来すぎて探すのが大変でした。また時間を見つけて投稿出来れば思っています。間違え等あればご指摘をお願い致します。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?