flask tutorialのDBにMongoDBを使う

flaskを勉強中。
flaskのtutorialを写経するだけではなーと思い、
tutorialではDBにsqlite3 を使っているところ、MongoDBを使ってみた。

github.com

以下備忘兼ねて、ハマったところなどメモ

PyMongoでCollectionをJoinするとき

tutorialのblog.py 36行目にて以下SQLでJoinしている箇所

    post = get_db().execute(
        'SELECT p.id, title, body, created, author_id, username'
        ' FROM post p JOIN user u ON p.author_id = u.id'
        ' WHERE p.id = ?',
        (id,)
    ).fetchone()

MongoDBでCollectonのjoinのやり方が分からず結構苦労した。
MongoDBでJoin相当の処理を実行する場合はaggregateメソッドを使用して同等の処理ができるらしい。

参考は以下

qiita.com

$lookup (aggregation) — MongoDB Manual

pymongoのAggregation Examplesを見ても$lookupなどの記載はなかったが、 ここのCollectionに関しての記載を読む感じ、行けそうだったので試してみたところ問題なく実行できた。
コードは以下

posts = db.post.aggregate([
    {"$lookup":
        {
            "from":"user",
            "localField":"author_id",
            "foreignField":"_id",
            "as":"userInfos"
        }
    },
    {"$unwind":"$userInfos"},
    {"$sort": { "updated" : -1 }},
    {"$project":
        {
            "id": "$_id",
            "title":"$title",
            "body": "$body",
            "updated": "$updated",
            "author_id": "$author_id",
            "username":"$userInfos.username",
        }
    }
    ])

取得した後、listに格納し直した上でrender_templateで変数を渡しているのだけど、
もっとスマートなやり方があるような気がする。。

pymongoでfind_oneメソッドにて_idでfilterする場合は

ObjectIdでなきゃ駄目
それ以上でも以下でもないが、、
以下はNGで

g.user = get_db().user.find_one({'_id': user_id})

以下はOK

g.user = get_db().user.find_one({'_id': ObjectId(user_id)})