Mongoコマンドとか初心者が苦しんだ所を書き残す。

# 初めに
初投稿です！
MongoDBを初めて触る機会があり、いろいろと詰まったことを忘れないために書き残します。  
まだ初心者エンジニアなので、勘違い等あるかと思いますが、間違い等ありましたら、指摘していただけると勉強になります！
書いてることは基本的には[MongoDB公式Document](https://docs.mongodb.com/manual/crud/)に載っているはずです。

## コマンド
###  GET-find
 シンプルな検索
 db.コレクション名.find({key: value})の形で検索をする。find()とすると全件を取得する。

    [sample]
    db.Collection.find({key1:fuga})

    And条件での検索
    db.Collection.find({ key1:fuga, key2:hoge })
    db.inventory.find( { $and: [ { key1:  10  }, { key2: 20 } ] } )

    Or条件での検索
    db.Collection.find({key1: [ fuga, hoge ] })
    db.inventory.find( { $or: [ { key1:  10  }, { key2: 20 } ] } )

    ソート
    sort({Key名:1(ASC) or -1(DESC)})で表現される。複数条件も可。
    db.Collection.find().sort({key1:1})

    カウント
    数値を入れるだけ。
    db.Collection.find().limit(10)

    オフセット
    数値を入れるだけ。
    db.Collectuon.find().skip(10)


###  INSERT-insert
Mongo
mongo特有のPrimaryKeyのようなものとして、_id(ObjectId)が自動で付与される。
また、Bsonの形式で保存される(このまま文字列として保存されるようなもの)ので、変数名を短くすると少し軽くなることもある(らしい)。  
また、今回はInsertですが、InsertOneやInsertManyのコマンドも知っていると便利でした！

    db.Collection.insert({'key1':'value'})

###  UPDATE-update
    db.Collection.update({条件式},{セット内容})
    db.Collection.update({key1:fuga},{$set: {key2:hogehoge}})

###  DELETE-delete
    db.Collection.delete({条件式})
    db.Collection.delete({key1:fuga})


#  AGGREGATEについて
Aggregateは集計用の関数です。
PipeLineとよばれる段階的な処理をする構造で、その処理の段階の単位をステージと表現されます。  
※イメージ(配列の形であらわされており、1要素あたり1ステージ)  
PipeLine[ Stage1, Stage2, Stage3]  
複雑な検索、集計処理を行う場合、Aggregateを用いることになると思います。  
このAggregateが使いこなせると、Mongoって便利やなぁ…ってなります。
Aggregateを使うとJoinっぽいことができます。Joinを通してAggregateの使い方を書き残します。

##  Joinがしたい
###  lookup  
Aggregateのパイプラインステージの$lookupを使うと、MongoでJoinっぽいことができます。  
簡単に言うと、ジョイン先のコレクションに対して、検索をして、その結果をasに書いた名前の配列としてジョイン元ドキュメントに追加します。  
また、lookupにはジョイン先、すなわち検索先コレクションに対してPipeLineを使うことができます。その場合、少し書き方が違うため、双方のパターンの実装例を示しておきます。(PipeLineを使わない実装はPipeLineを使う実装を簡略化したものだと思われます。)


実装例  
PipeLineを使わない(Join先に検索をしない)  

    db.Collection.aggregate([{$lookup:
                                from: <ジョイン先のコレクション名>,
                                localField: <ジョイン元の紐づけるためのField>,
                                foreignField: <ジョイン先の紐づけるためのField>,
                                as: <ジョイン情報の名前>
                            }])
PipeLineを使う(Join先に検索をする)  

    db.Collection.aggregate([
                            {
                                $lookup:{
                                from: <ジョイン先のコレクション名>,
                                localField: <ジョイン元の紐づけるためのField>,
                                foreignField: <ジョイン先の紐づけるためのField>,
                                as: <ジョイン情報の名前>
                                }
                            },
                            {
                                $unwind:　$ + <ジョイン情報の名前>
                            }
                            ])



###  unwind
上記のlookupで取得した結果は配列になっています。配列に対する検索をする場合、$unwindを使って、配列を展開する必要があります。  
展開するイメージとしては、下記のようになります。  

unwindイメージ

    {
        _id: 123,
        name: "伝説太郎",
        hobby: ["釣り", "買い物", "キャンプ"]
    }

↓↓↓

    {
        _id: 123,
        name: "山田太郎",
        hobby: "釣り"
    },
    {
        _id: 123,
        name: "山田太郎",
        hobby: "買い物"
    },
    {
        _id: 123,
        name: "山田太郎",
        hobby: "キャンプ"
    },

実装例  
※Mongo公式様のサンプルから引用です。  

    db.Collection.aggregate([
                            {
                                $lookup:{
                                from: <ジョイン先のコレクション名>,
                                localField: <ジョイン元の紐づけるためのField>,
                                foreignField: <ジョイン先の紐づけるためのField>,
                                as: <ジョイン情報の名前>
                                }
                            },
                            {
                                $unwind:　$ + <ジョイン情報の名前>
                            }
                            ])

    db.Collection.aggregate([
                                {
                                $lookup:
                                    {
                                    from: <ジョイン先のコレクション名>,　
                                    // letはPipeLineで使用する変数を指定します
                                    let: { order_item: "$item", order_qty: "$ordered" },
                                    pipeline: [
                                        { $match:
                                            { $expr:
                                                { $and:
                                                [
                                                    { $eq: [ "$stock_item",  "$$order_item" ] },
                                                    { $gte: [ "$instock", "$$order_qty" ] }
                                                ]
                                                }
                                            }
                                        },
                                        { $project: { stock_item: 0, _id: 0 } }
                                    ],
                                    as: <ジョイン情報の名前>
                                    }
                                }
                            ])


### match
ようやく検索です。findの時の書き方とそこまで変わりはありません。  
$exprについては↓にちょっとだけ書きました。

    { $match:
               { $expr:
                       { $and:
                       [
                           { $eq: [ "$stock_item",  "$$order_item" ] },
                           { $gte: [ "$instock", "$$order_qty" ] }
                       ]
                       }
               }
    }


## 比較演算子
### 同一ドキュメント内の変数を比較する場合
\$exprを用いる。パイプラインステージのlookupの時の$letに近いもの。  
実装例

    $expr: {
              $and: [
                { $eq: ["$hobby", "$name"] },
                { $gt: ["$age", "$date"] }]
            }

# おわりに
自分用の忘備録なので読みづらい文章で申し訳ないです。
私と同じ初心者さんで、わからないところや詰まってること等ありましたら、気軽にコメントしてください。
私にわかる範囲でならお答えします！

## 参考にさせていただいたページ様方
[MongoDB コマンドメモとか書き](https://qiita.com/svjunic/items/285e9cf20169d70aa1fa)
[MongoDB で コレクションを結合する 方法](https://garafu.blogspot.com/2018/02/mongodb-lookup.html)
[MongoDBのAggregationでRDBみたいな使い方](https://qiita.com/mtitg/items/c342fbd55f6aea047182)