溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

MongoDB高級(jí)語(yǔ)法

發(fā)布時(shí)間:2020-07-11 18:09:41 來源:網(wǎng)絡(luò) 閱讀:690 作者:梁十八 欄目:關(guān)系型數(shù)據(jù)庫(kù)

and操作:

????隱式and操作:

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

????顯式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在執(zhí)行or操作時(shí)會(huì)遵循一個(gè)"短路原則":只要前面的條件滿足了,那后面的條件直接跳過。如果age大于28 ,那就不需要去檢查salary的值是多少。只有在age不滿足查詢條件時(shí),才會(huì)去檢查salary的值)

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

????而這里去可以把or兩邊的都顯示出來:

?? ???? > db.getCollection("the_table").find()
?? ??? ?......
?? ??? ?{ "_id" : ObjectId("5d10400adc4728bc5f52f3ca"), "username" : "張三" }
?? ??? ?{ "_id" : ObjectId("5d104011dc4728bc5f52f3cb"), "username" : "李四" }
?? ??? ?> db.getCollection("the_table").find({"$or":[{"username":"張三"},{"username":"李四"}]})
?? ??? ?{ "_id" : ObjectId("5d10400adc4728bc5f52f3ca"), "username" : "張三" }
?? ??? ?{ "_id" : ObjectId("5d104011dc4728bc5f52f3cb"), "username" : "李四" }
?? ??? ?>



嵌入式文檔的查詢:

??? MongoDB高級(jí)語(yǔ)法

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

????查詢所有followed大于10的數(shù)據(jù):

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

????如需要在返回的查詢結(jié)果中只顯示嵌入式文檔中的部分內(nèi)容,也可以使用點(diǎn)號(hào)來實(shí)現(xiàn)。例如只返回"name"和"user_id"這兩個(gè)字段,查詢語(yǔ)句:

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

???


包含與不包含:

????查出所有size包含M的數(shù)據(jù):

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

????????MongoDB高級(jí)語(yǔ)法

????查出所有size不包含M的數(shù)據(jù):

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

????????MongoDB高級(jí)語(yǔ)法

????數(shù)組中有元素在另一個(gè)范圍空間內(nèi):

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



數(shù)組應(yīng)用:

????根據(jù)數(shù)組長(zhǎng)度查詢數(shù)據(jù):

????????從數(shù)據(jù)集the_table中查詢所有price長(zhǎng)度為2的記錄:

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

????????????MongoDB高級(jí)語(yǔ)法

????根據(jù)索引查詢數(shù)據(jù)(索引是從0 開始的)

????????查詢所有“ size ”的第1個(gè)(索引為0)數(shù)據(jù)為“ S ”的記錄,查詢語(yǔ)句為:

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

????????????MongoDB高級(jí)語(yǔ)法

????????使用索引也可以比較大小。例如,查詢“price ”第1 個(gè)數(shù)據(jù)大于500 的所有記錄:

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

????????????MongoDB高級(jí)語(yǔ)法



高級(jí)更新:

????最好用$push或$addToSet,這兩個(gè)命令都是往數(shù)組中添加數(shù)據(jù),但$addToSet是唯一的,阻止了重復(fù)數(shù)據(jù)

????????db.getCollection("the_table").update(
?? ??? ??? ?{"favorites.movies": "Cassablanca"},
?? ??? ??? ?{"$addToSet": {"favorites.movies": "the maltese falcon"}},
?? ??? ??? ?false,
?? ??? ??? ?true
?? ??? ?)

??????? 第一個(gè)參數(shù):匹配電影列表中包含Cassablanca的用戶

????????第二個(gè)參數(shù):使用$addToSet添加the maltese falcon到列表中

????????第三個(gè)參數(shù):false,控制是否允許upsert。這個(gè)命令告訴更新操作,當(dāng)一個(gè)文檔不存在的時(shí)候是否插入它,這取決于更新操作是操作符更新還是替換更新

????????第四個(gè)參數(shù):true,表示是否更新多個(gè)更新。默認(rèn)情況下,mongodb更新只針對(duì)第一個(gè)匹配文檔。如果想更新所有匹配文檔,就必須顯示指定這個(gè)參數(shù)。


刪除數(shù)據(jù):

????db.user.remove({"favorites.cities":"Cheyenne"})

????注意:remove()操作不會(huì)刪除集合,它只會(huì)刪除集合中的某個(gè)文檔。我們可以把它和sql中的delete命令類比。如果要?jiǎng)h除集合以及附帶的索引數(shù)據(jù),可以用drop()方法:

????db.user.drop()


MongoDB的聚合查詢:

????使用聚合功能,可以直接讓MongoDB來處理數(shù)據(jù)。聚合功能可以把數(shù)據(jù)像放入傳送帶一樣,先把原始數(shù)據(jù)按照一定的規(guī)則進(jìn)行篩選處理,然后通過多個(gè)不同的數(shù)據(jù)處理階段來處理數(shù)據(jù),最終輸出一個(gè)匯總的結(jié)果。

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

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

????如果聚合有至少一個(gè)階段,那么每一個(gè)階段都是一個(gè)字典。不同的階段負(fù)責(zé)不同的事情,每一個(gè)階段有一個(gè)關(guān)鍵字。有專門負(fù)責(zé)篩選數(shù)據(jù)的階段“ $match ’3 ,有專門負(fù)責(zé)宇段相關(guān)的階段“ $pr句ect”,有專門負(fù)責(zé)數(shù)據(jù)分組的階段“$group"等。聚合操作有幾十個(gè)不同的階段關(guān)鍵字

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


????????從the_table數(shù)據(jù)集中,查詢age大于等于27,且sex為“女”的所有記錄:

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

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

????????這兩種寫法,核心查詢語(yǔ)句{"age": {"$gte": 27} , "sex":"女"}完全一樣。聚合查詢操作中的{"$match":{和find完全一樣的查詢表達(dá)式}}","$match"作為一個(gè)字典的Key,字典的Value和"find()"第1個(gè)參數(shù)完全相同。"find()"第1個(gè)參數(shù)能怎么寫,這里就能怎么寫。

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

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

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


????篩選與修改字段:

????????$project來實(shí)現(xiàn)一個(gè)己經(jīng)有的功能一一只返回部分字段(這里的字段過濾語(yǔ)句與find()第2個(gè)參數(shù)完全相同)

????????????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}}}
????????])

????????MongoDB高級(jí)語(yǔ)法

????????(newfield是原來沒有的字段)

????

????復(fù)制現(xiàn)有字段:

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

????????MongoDB高級(jí)語(yǔ)法

????????

????修改現(xiàn)有字段的數(shù)據(jù):

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

????????MongoDB高級(jí)語(yǔ)法


????注意:這并不會(huì)改變數(shù)據(jù)庫(kù)里的數(shù)據(jù),只是改變輸出的數(shù)據(jù)

????????MongoDB高級(jí)語(yǔ)法

????????(數(shù)據(jù)并沒有變化)


????抽取嵌套字段:

????????上面的:添加新字段、復(fù)制現(xiàn)有字段、修改現(xiàn)有字段的數(shù)據(jù)等,看起來并沒有卵用,而下面的例子就有用了:

????????????如果用find(),想返回user_id和name,則查詢語(yǔ)句為:

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

????????????返回結(jié)果為:

????????????????MongoDB高級(jí)語(yǔ)法

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

????????????現(xiàn)在用$project將嵌套字段中的內(nèi)容抽?。?/p>

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

????????????????MongoDB高級(jí)語(yǔ)法


????處理字段特殊值:

????????? 如果想添加一個(gè)字段,但是這個(gè)字段的值就是數(shù)字“ 1 ”會(huì)怎么樣?
????????? 如果添加一個(gè)字段,這個(gè)字段的值就是一個(gè)普通的字符串,但不巧正好以“$”開頭,又會(huì)怎么樣呢?

??????? 關(guān)鍵字:$literal

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

????????MongoDB高級(jí)語(yǔ)法


????分組操作:

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

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

????????????MongoDB高級(jí)語(yǔ)法

????????????分組操作雖然也能實(shí)現(xiàn)去重操作,但是它返回的數(shù)據(jù)格式與distinct函數(shù)是不一樣的。distinct函數(shù)返回的是數(shù)組,而分組操作返回的是幾條記錄

????????去重并統(tǒng)計(jì):

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

??????????? MongoDB高級(jí)語(yǔ)法

????????原則上,$sum和$avg的值對(duì)應(yīng)的字段的值應(yīng)該都是數(shù)字。如果強(qiáng)行使用值為非數(shù)字的字段,那么$sum會(huì)返回0, $avg會(huì)返回null。而字符串是可以比較大小的,所以,$max與$min可以正常應(yīng)用到字符串型的字段

????????還可以使用$sum的值為數(shù)字1來統(tǒng)計(jì)多少條記錄:

????????????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"}}}
????????????])

????????????MongoDB高級(jí)語(yǔ)法


????分組/去重、最新一條數(shù)據(jù):

????????MongoDB高級(jí)語(yǔ)法

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

????????MongoDB高級(jí)語(yǔ)法

????

????可以取最新的數(shù)據(jù),自然可以取最早的數(shù)據(jù):

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

????????MongoDB高級(jí)語(yǔ)法

????

????拆分?jǐn)?shù)組(用關(guān)鍵字:$unwind):

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

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

????????MongoDB高級(jí)語(yǔ)法

????????還可以把price數(shù)組也拆分:

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

????????MongoDB高級(jí)語(yǔ)法



????聯(lián)集合查詢:

????????MongoDB高級(jí)語(yǔ)法

????????MongoDB高級(jí)語(yǔ)法

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

????????其中的“主集合”與“被查集合”需要搞清楚。如果順序搞反了, 則結(jié)果會(huì)不同。
????????例如, 現(xiàn)在需要在做博集合中查詢用戶信息, 那么主集合就是微博集合, 被查集合就是用戶集合。于是查詢語(yǔ)句可以寫為以下:

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

????????????MongoDB高級(jí)語(yǔ)法

????????????(這里user_info字段之所以會(huì)是一個(gè)數(shù)組,是因?yàn)楸徊樵兗现锌赡苡卸鄺l記錄都滿足條件,只有使用數(shù)組才能把它們都保存下來。由于用戶集合每一個(gè)記錄都是唯一的,所以這個(gè)數(shù)組只有一個(gè)元素)

????????????聯(lián)集合查詢并美化結(jié)果:

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

????????????????MongoDB高級(jí)語(yǔ)法

????????????當(dāng)然,還可以將聯(lián)集合查詢拆分結(jié)果返回特定內(nèi)容:

????????????????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"
?? ??? ?????????????}}
??? ????????????])

????????????????MongoDB高級(jí)語(yǔ)法

????????????以用戶為基準(zhǔn)聯(lián)集合查詢:

????????????????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"
???? ????????????? ?}}
??? ????????????])

????????????????MongoDB高級(jí)語(yǔ)法

???????????

??????????? 還可以指定只查某人的:

????????????????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的索引)

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI