MongoDB高級語法

and操作:

    隱式and操作:

        db.getCollection("the_table").find({"age":{"$gt":20},"sex":"男"})   //對age與sex這兩個字段的查詢條件需要同時滿足

    顯式and操作:

        db.getCollection("the_table").find({"$and":[{"age":{"$gte":20}},{"address":"裏世界"}]})

    顯式、隱式混用:

        db.getCollection("the_table").find({
            "id":{"$lt": 10},
            "$and": [{"age": {"$gt": 20}}, {"sex": "男"}]
        })

    不能寫成隱式and操作的例子:

        db.getCollection("the_table").find({
            "$and": [
                {"$or": [{"age": {"$gt": 28}}, {"salary": {"$gt": 9900}}]},
                {"$or": [{"sex": "男"}, {"id": {"$lt": 20}}]}
            ]
        })

or操作:

    年齡大於28,或工資大於9900的:

        db.getCollection("the_table").find({
            "$or": [{"age": {"$gt": 28}},{"salary":{"$gt": 9900}}]
        })

    (注意:mongodb在執行or操作時會遵循一個"短路原則":只要前面的條件滿足了,那後面的條件直接跳過。如果age大於28 ,那就不需要去檢查salary的值是多少。只有在age不滿足查詢條件時,纔會去檢查salary的值)

    OR操作一定是顯式的,不存在隱式的OR操作



嵌入式文檔的查詢:

    圖片.png

    嵌入字段只是定位的時候多了一步。除此之外,嵌入字段和普通字段沒有區別。

    查詢所有followed大於10的數據:

        db.getCollection("the_table").find({"user.followed": {"$gt": 10}})

    如需要在返回的查詢結果中只顯示嵌入式文檔中的部分內容,也可以使用點號來實現。例如只返回"name"和"user_id"這兩個字段,查詢語句:

        db.getCollection("the_table").find(
            {"user.followed": {"$gt": 10}},
            {"_id": 0, "user.name": 1, "user.user_id": 1}
        )

   


包含與不包含:

    查出所有size包含M的數據:

        db.getCollection("the_table").find({"size": "M"})

        圖片.png

    查出所有size不包含M的數據:

        db.getCollection("the_table").find({"size": {"$ne": "M"}})

        圖片.png

    數組中有元素在另一個範圍空間內:

        db.getCollection("the_table").find({"price": {"$lt": 300, "$gt": 200}}



數組應用:

    根據數組長度查詢數據:

        從數據集the_table中查詢所有price長度爲2的記錄:

            db.getCollection("the_table").find({"price": {"$size": 2}})

            圖片.png

    根據索引查詢數據(索引是從0 開始的)

        查詢所有“ size ”的第1個(索引爲0)數據爲“ S ”的記錄,查詢語句爲:

            db.getCollection("the_table").find({"size.0": "S"})

            圖片.png

        使用索引也可以比較大小。例如,查詢“price ”第1 個數據大於500 的所有記錄:

            db.getCollection("the_table").find({"price.0": {"$gt": 500}})

            圖片.png



MongoDB的聚合查詢:

    使用聚合功能,可以直接讓MongoDB來處理數據。聚合功能可以把數據像放入傳送帶一樣,先把原始數據按照一定的規則進行篩選處理,然後通過多個不同的數據處理階段來處理數據,最終輸出一個彙總的結果。

    聚合操作的命令爲"aggregate",基本格式爲:collection.aggregate([階段1,階段2,階段3, ……,階段N])

    聚合操作可以有0 個、l 個或者多個階段。如果有0 個階段,則查詢命令寫爲:collection.aggregate()。那麼它的作用和collection.find() 一樣

    如果聚合有至少一個階段,那麼每一個階段都是一個字典。不同的階段負責不同的事情,每一個階段有一個關鍵字。有專門負責篩選數據的階段“ $match ’3 ,有專門負責宇段相關的階段“ $pr句ect”,有專門負責數據分組的階段“$group"等。聚合操作有幾十個不同的階段關鍵字

    一般情況下,並非所有的數據都需要被處理,因此大多數時候聚合的第一個階段是數據篩選。就像find()一樣,把某些滿足條件的數據選出來以便後面做進一步處理。數據篩選的關鍵字爲$match,它的用法爲:collection.aggregate([{"$match":{和find 完全一樣的查詢表達式}}])


        從the_table數據集中,查詢age大於等於27,且sex爲“女”的所有記錄:

            db.getCollection("the_table").aggregate([
                {"$match": {"age": {"$gte": 27}, "sex": "女"}}
            ])

        從查詢結果來看,這一條聚合查詢語句的作用完全等同於:
            db.getCollection("the_table").find({"age": {"$gte": 27}, "sex": "女"})

        這兩種寫法,核心查詢語句{"age": {"$gte": 27} , "sex":"女"}完全一樣。聚合查詢操作中的{"$match":{和find完全一樣的查詢表達式}}","$match"作爲一個字典的Key,字典的Value和"find()"第1個參數完全相同。"find()"第1個參數能怎麼寫,這裏就能怎麼寫。

        例如,查詢所有age大於28或sex爲男的記錄,聚合查詢可以寫爲:

            db.getCollection("the_table").aggregate([
                {"$match": {"$or": [{"age": {"$gt": 28}}, {"sex": "男"}]}}
            ])

        從效果上看,使用聚合查詢與直接使用“自nd()” 效果完全相同,而使用聚合查詢還要多敲幾次鍵盤,那它的好處在哪裏呢?聚合操作的好處在於“ 組合” 。接下來會講到更多的聚合關鍵字,把這些關鍵字組合起來才能體現出聚合操作的強大。


    篩選與修改字段:

        $project來實現一個己經有的功能一一只返回部分字段(這裏的字段過濾語句與find()第2個參數完全相同)

            db.getCollection("the_table").aggregate([
                {"$project": {"_id":0, "sex":1, "age":1}}
            ])

    先篩選記錄,再過濾字段:

        db.getCollection("the_table").aggregate([

            {"$match": {"age": {"$gt": 28}}}

            {"$project": {"_id":0, "sex":1, "age":1}},
        ])


    添加新字段:

        db.getCollection("the_table").aggregate([
            {"$project": {"_id":0, "sex":1, "age":1, "newfield": "hello world"}},
            {"$match": {"age": {"$gt": 28}}}
        ])

        圖片.png

        (newfield是原來沒有的字段)

    

    複製現有字段:

        db.getCollection("the_table").aggregate([
            {"$match": {"age": {"$gt": 28}}},
            {"$project": {"_id":0, "sex":1, "age":1, "newfield": "$age"}}
        ])

        圖片.png

        

    修改現有字段的數據:

        db.getCollection("the_table").aggregate([
            {"$match": {"age": {"$gt": 28}}},
            {"$project": {"_id":0, "sex":1, "age":1, "newfield": "this is new field"}}
        ])

        圖片.png


    注意:這並不會改變數據庫裏的數據,只是改變輸出的數據

        圖片.png

        (數據並沒有變化)


    抽取嵌套字段:

        上面的:添加新字段、複製現有字段、修改現有字段的數據等,看起來並沒有卵用,而下面的例子就有用了:

            如果用find(),想返回user_id和name,則查詢語句爲:

                db.getCollection("the_table").find({},{"user.name":1, "user.user_id":1})

            返回結果爲:

                圖片.png

                (顯然,嵌套字段處理起來並不方便)

            現在用$project將嵌套字段中的內容抽取:

                db.getCollection("the_table").aggregate([
                    {"$project": {"name":"$user.name", "user_id":"$user.user_id"}}
                ])

                圖片.png


    處理字段特殊值:

        • 如果想添加一個字段,但是這個字段的值就是數字“ 1 ”會怎麼樣?
        • 如果添加一個字段,這個字段的值就是一個普通的字符串,但不巧正好以“$”開頭,又會怎麼樣呢?

        關鍵字:$literal

        db.getCollection("the_table").aggregate([
            {"$match": {"age": {"$gt": 28}}},
            {"$project": {"_id":0, "id":1, "hello": {"$literal":"$normalstring"}, "abcd":{"$literal":1}}}
        ])

        圖片.png


    分組操作:

        去重的格式:db.getCollection("the_table").aggregate([{"$group": {"_id": "$被去重的字段名"}}])

            db.getCollection("the_table").aggregate([
                {"$group": {"_id": "$name"}}
            ])

            圖片.png

            分組操作雖然也能實現去重操作,但是它返回的數據格式與distinct函數是不一樣的。distinct函數返回的是數組,而分組操作返回的是幾條記錄

        去重並統計:

            db.getCollection("the_table").aggregate([
                {"$group": {"_id": "$name","max_age":{"$max":"$age"},"min_age":{"$min":"$age"},"avg_age":{"$avg":"$age"},"sum_age":{"$sum":"$age"}}}
            ])

            圖片.png

        原則上,$sum和$avg的值對應的字段的值應該都是數字。如果強行使用值爲非數字的字段,那麼$sum會返回0, $avg會返回null。而字符串是可以比較大小的,所以,$max與$min可以正常應用到字符串型的字段

        還可以使用$sum的值爲數字1來統計多少條記錄:

            db.getCollection("the_table").aggregate([
                {"$group": {"_id": "$name","doc_count":{"$sum":1},"max_age":{"$max":"$age"},"min_age":{"$min":"$age"},"avg_age":{"$avg":"$age"},"sum_age":{"$sum":"$age"}}}
            ])

            圖片.png


    分組/去重、最新一條數據:

        圖片.png

        db.getCollection("the_table").aggregate([
            {"$group": {"_id": "$name","age":{"$last":"$age"},"address":{"$last":"$address"}}}
        ])

        圖片.png

    

    可以取最新的數據,自然可以取最早的數據:

        db.getCollection("the_table").aggregate([
            {"$group": {"_id": "$name","age":{"$first":"$age"},"address":{"$first":"$address"}}}
        ])

        圖片.png

    

    拆分數組(用關鍵字:$unwind):

        格式:collection.aggregate([{"$unwind":"$字段名"}])

        db.getCollection("the_table").aggregate([
            {"$unwind":"$size"}
        ])

        圖片.png

        還可以把price數組也拆分:

        db.getCollection("the_table").aggregate([
            {"$unwind":"$size"},
            {"$unwind":"$price"}
        ])

        圖片.png



    聯集合查詢:

        圖片.png

        圖片.png

        主集合.aggregate([
            {
                "$lookup": {
                    "from": "被查集合名",
                    "localField": "主集合的字段",
                    "foreignField": "被查集合的字段",
                    "as": "保存查詢結果的字段名"
                }
            }
        ])

        其中的“主集合”與“被查集合”需要搞清楚。如果順序搞反了, 則結果會不同。
        例如, 現在需要在做博集合中查詢用戶信息, 那麼主集合就是微博集合, 被查集合就是用戶集合。於是查詢語句可以寫爲以下:

            db.getCollection("example_post").aggregate([
                {"$lookup":{
                    "from": "example_user",
                    "localField": "user_id",
                    "foreignField": "id",
                    "as": "user_info"
                }}
            ])

            圖片.png

            (這裏user_info字段之所以會是一個數組,是因爲被查詢集合中可能有多條記錄都滿足條件,只有使用數組才能把它們都保存下來。由於用戶集合每一個記錄都是唯一的,所以這個數組只有一個元素)

            聯集合查詢並美化結果:

                db.getCollection("example_post").aggregate([
                    {"$lookup":{
                        "from": "example_user",
                        "localField": "user_id",
                        "foreignField": "id",
                        "as": "user_info"
                    }},
                    {"$unwind":"$user_info"}
                ])

                圖片.png

            當然,還可以將聯集合查詢拆分結果返回特定內容:

                db.getCollection("example_post").aggregate([
                    {"$lookup":{
                        "from": "example_user",
                        "localField": "user_id",
                        "foreignField": "id",
                        "as": "user_info"
                    }},
                    {"$unwind":"$user_info"},
                    {"$project":{
                        "content": 1,
                        "post_time": 1,
                        "name": "$user_info.name",
                        "work": "$user_info.work"
                    }}
                ])

                圖片.png

            以用戶爲基準聯集合查詢:

                db.getCollection("example_user").aggregate([
                    {"$lookup":{
                        "from": "example_post",
                        "localField": "id",
                        "foreignField": "user_id",
                        "as": "weibo_info"
                    }},
                    {"$unwind":"$weibo_info"},
                    {"$project":{
                        "name": 1,
                        "work": 1,
                        "content": "$weibo_info.name",
                        "post_time": "$weibo_info.work"
                    }}
                ])

                圖片.png

           

            還可以指定只查某人的:

                db.getCollection("example_user").aggregate([
                    {"$match": {"name": "張三瘋"}},
                    {"$lookup":{
                        "from": "example_post",
                        "localField": "id",
                        "foreignField": "user_id",
                        "as": "weibo_info"
                    }},
                    {"$unwind":"$weibo_info"},
                    {"$project":{
                        "content": 1,
                        "post_time": 1,
                        "name": "$weibo_info.name",
                        "work": "$weibo_info.work"
                    }}
                ])

                (從性能上講,建議把$match放在最前面,這樣可以充分用到mongodb的索引)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章