摘要:舉個栗子你有一個箱子,里面有一個兒子級別和孫子級別的箱子共層現在你把孫子級別的箱子多帶帶拿出來,把整個箱子替換掉就是這種思想。。。自己體會吧這種語法,好像列表的切片賦值。。官方建議我們用它的好處是把和由兩個函數調用變為個參數傳進去了。
閱讀須知
由于是對比書寫: M: 代表 Mongo原生語法 P: 代表 PyMongo書寫方法 后面提到:”同上“ 字眼: 意思就是 Mongo 和 PyMongo 語句是一模一樣的, 一個字都不差,復制上去,可以直接運行 (也許你很好奇,為什么 一個是Python語言里的PyMongo,一個是Mongo) 他們的語句為什么可以做到一模一樣 ?? 答:因為 Mongo和Python都可以 給變量賦值, PyMongo的語法設計也是模仿Mongo的。 所以:我巧妙的 把二者的變量設為同一個,函數90%都一致, 所以整條語句就一模一樣了! 主要語法區別: 1. 函數命名 Mongo 方法函數大都以 駝峰命名 PyMongo方法函數大都以 _ 下劃線分割命名 2. 函數參數 Mongo : 基本都是 {} + [] 各組組合格式 PyMongo:同上, 但{}的 key需要使用字符串格式, 有些情況,還需要使用命名參數代替 {} 3. 空值 與 Bool Mongo: null true false PyMongo: None True False前置安裝配置環境
客戶端連接:
pip install pymongo import pymongo M: Mongo P: cursor = pymongo.MongoClient("ip",port=27017)
選擇數據庫:
M: use test P: db = cursor["test"] # 記住這個db, 下面復用這個參數
選擇集合: (記住table變量名,下面就直接用他們了) 注意,注意,注意
M: table = db.zhang P: table = db["zhang"] 注:選擇庫,選擇集合的時候 注意事項: Mongo中: xx.xx 用 . 的語法 PyMongo中:也可以 用 xx.xx 這樣, 但是這樣用在PyCharm中沒有語法提示 所以提倡 xx["xx"] 用索引的方式使用
Mongo 與 PyMongo 返回結果的游標比較
Mongo中: 大多數查詢等結果返回都是游標對象 如果不對游標遍歷,那么Mongo的游標會默認為你取出 前 20 個 值 當然,你也可以索引取值 關閉操作: .close() PyMongo中: 同樣,大多數查詢等結果返回都是游標對象(如果你學過ORM,可以理解游標就像 ORM的查詢集) 所以必須通過 list() 或 遍歷 或 索引 等操作才能真正取出值 關閉操作: .close() 或者 用 Python 的 with 上下文協議增
save()
M: table.save({}) # 估計要廢棄了 P: 將要被廢棄 用insert_one代替它
insert()
M: table.insert() # 包括上面兩種,可以一個 {},可以多個 [{},{}] P: PyMongo源碼明確說明,insert()語法將被廢棄,請用 insert_one({}) 和 insert_many([])代替
insert_one() 和 insert_many()
M: table.insertOne( {} ) # 駝峰 table.insertMany([ {},{} ]) # 駝峰 P: table.insert_one( {} ) # 下劃線 table.insert_many([ {},{} ]) # 下劃線刪
remove()
參數1:刪除查詢條件 參數2:刪除選項 M: table.remove({"name":"zhangsan"}, {"justOne": true}) # 我更喜歡用delete的 P: PyMongo中,此方法將被廢棄。 將會被 delete_one() 和 delete_many() 代替
deleteOne() # 只刪除一條
M: table.deleteOne({"name": "lin3"}) P: table.delete_one({"name": "lin3"}) #
deleteMany() # 刪除多條
M: table.deleteMany({"name": "lin3"}) P: table.delete_many({"name": "lin3"}) 注意: 不知道這兩個函數是否讓你想起了前面講的 insertOne 和 insertMany,他們看起來很像,語法不同: insertMany([]) # 參數需要用 [] 包起來 deleteMany({}) # 參數不需要 注意2: table.deleteMany({}) # 空 {}, 代表刪除所有文檔 (慎行,慎行,慎行)
刪除整個集合:
table.drop() # 刪除集合(連同 所有文檔, 連同 索引,全部刪除)改
""" 文檔修改, 注意: _id 不可修改 """
三種更新方法:
1. update(將要廢棄,可跳過,直接看2,3點的方法) update({查詢條件}, {更新操作符} , {更新選項}) M: table.update({"name": {"$regex":"li"}},{"$set":{"name":"lin2"}}, {multi: true}) P: table.update({"name": {"$regex": "li"}}, {"$set": {"name": "lin3"}},multi=True) 注意1: 第三個參數 multi如果不設置,默認只更新一條文檔,設置為 true ,就會更新多條文檔 注意2: Mongo寫法: {multi: true} # Mongo 和往常一樣,采用json格式, true小寫 Python寫法: multi = True # python是采用命名參數來傳遞, True大寫 2. updateOne(更新一條) M: updateOne( {查詢條件}, {更新操作符} ) P: update_one 3. updateMany(更新多條) M: updateMany( {查詢條件}, {更新操作符} ) 其實參數是一模一樣的,只不過方法名區分 P: update_many 注: 這三個方法的參數 是基本一模一樣的 所以下面講具體 {查詢條件}, {更新操作符} 時 就統一用 update()來寫了
普通更新操作符:
$set(更新)
# 注:規則就是:"有則改之, 無則添加" M: table.update({"5":5},{"$set": {"lin": [5,6,7,8]} }) P: 同上 微擴展(關于內嵌數組): table.update({"5":5},{"$set": {"lin.0": "呵呵" }) # lin.0代表數組的第一個元素 當數組的索引越界,這個時候就視為數組的添加操作。 eg: 假定我們給 lin.10 一個值,那么 中間空出的那么多索引,會自動填充 null
$unset(刪除)
# 注:刪除的鍵對應的value可以隨便寫,寫啥都會刪除, 寫 "" 只是為了語義明確(規范) M: table.update({"6":6}, {"$unset": {"6":""}}) # 把此條記錄的 "6" 字段刪除 P: 同上 微擴展(關于嵌套數組): table.update({"5":5}, {"$unset": {"lin.0":""}}) # lin.0同樣代表數組第一個元素 注:數組的刪除 并不是真正的刪除, 而是把值 用 null 替換
$rename(改名,替換)
M: table.update({"name":"lin"}, {"$rename":{"name":"nick"}}) # name變成了nick P: 同上 微擴展(文檔嵌套): 如果文檔是嵌套的 eg: { a: {b:c} } M: table.update({"lin":"lin"}, {"$rename": {"a.b":"d"}}) P: 同上 結果 => {"a" : { }, "d" : "c" } 解析: b 屬于 子文檔 a.b 表示 通過父文檔的a 來取出 子文檔的b 如果整體a.b被 rename為 d,那么 d會被安排到父文檔的層級里,而a設為空。 舉個栗子: 你有一個箱子,里面 有一個 兒子級別 和 孫子級別 的箱子 (共3層) 現在你把 孫子級別的箱子 多帶帶拿出來, 把整個箱子替換掉 就是這種思想。。。自己體會吧 (這種語法,好像Python列表的切片賦值。。形容可能不太恰當)
$inc:
{$inc: { "age": -2}} # 減少兩歲,正數表示加法,負數表示減法,簡單,不舉例了 特例:如果字段不存在,那么,此字段會被添加, 并且值就是你設定的值(0+n=n)
$mul:
{$mul: { "age": 0.5}} # 年齡除以2,整數表示乘法,小數表示除法,簡單,不舉例了 特例:如果字段不存在,那么,此字段會被添加, 并且值為0 (0*n=0)
$min
{$min: { "age": 30}} # 30比原有值小:就替換, 30比原有值大,則不做任何操作
$max
{$max: { "age": 30}} # 30比原有值大:就替換, 30比原有值小,則不做任何操作 特例:min和max特例相同,即如果字段不存在,那么,此字段會被添加, 并且值就是你設定的值
數組更新操作符:
""" 單數組: xx 內嵌數組: xx.索引 """
$addToSet(有序,無重復,尾部添加)
原始數據: {"1":1} M: table.update({"1":1}, {"$addToSet":{"lin":[7,8]}}) P: 同上 結果 => {"1": 1,"lin": [ [7, 8 ] ]} # [7,8] 整體插入進來, 特別注意這是二級列表
$each ( 給[7,8]加個 $each,注意看結果變化 )
M: table.update({"1": 1}, {"$addToSet": {"lin": {"$each":[7, 8]} }}) P: 同上 結果 => {"1": 1, "lin": [7,8]} # 7,8多帶帶插入進來,參考python的 * 解構
$push(數據添加, 比$addToSet強大,可任意位置,可重復)
""" 補充說明: $addToSet:添加數據有重復,會自動去重 $push :添加數據有重復,不會去重,而是直接追加 """ 原始數據: {"1":1} M: table.update( { "1": 1 }, { "$push": { "lin": { "$each": [ {"a": 5, "b": 8 }, { "a": 6, "b": 7 }, {"a": 7, "b": 6 } ], "$sort": { "a": -1 }, "$position": 0, "$slice": 2 }}}) # 這里為了清晰點,我就把所有括號折疊起來了 P: 同上 結果 => {"1" : 1, "lin" : [ { "a" : 7, "b" : 6 }, { "a" : 6, "b" : 7 } ] } 終極解析: 1. 添加數組: 先走 $sort => 根據a 逆序排列 2. 再走 $position, 0表示:索引定位從0開始 3. 再走 $slice, 2表示: 取2個 4. 最后走 $each,把數組元素逐個放進另一個數組,說過的,相當于python的 * 解構操作,
$pop(只能 刪除 頭或尾 元素)
M: table.update({"a": a}, {"$pop": {"lin": 1}}) # 刪除最后一個 P: 同上 注1:$pop參數, 1代表最后一個, -1代表第一個。 這個是值得注意一下的,容易記反 注2:如果全部刪沒了,那么會剩下空[], 而不是徹底刪除字段
$pull (刪除 任何位置 的 指定的元素)
M: table.update({"1": 1},{"$pull":{ "lin":[7,8]}}) # 刪除數組中[7,8]這個內嵌數組 P: 同上
$pullAll(基本和 $pull 一致)
M: table.update({"1": 1},{"$pullAll":{ "lin":[ [7,8] ]}}) # 同$pull,但多了個 [] P: 同上 注: $pull 和 $pullAll 針對于 內嵌文檔 和 內嵌數組 有細小差別, 差別如下: 內嵌數組: $pull 和 $pullAll 都嚴格要求內嵌數組的 排列順序,順序不一致,則不返回 內嵌文檔: $pullAll : 嚴格要求內嵌文檔的順序, 順序不一致,則 不返回 $pull : 不要求內嵌文檔的循序, 順序不一致,一樣可以返回查
""" 第一個參數的條件是 篩選出 數據的記錄(文檔) 第二個參數的條件是 篩選出 數據的記錄中的 屬性(字段),不配置 就是 默認 取出所有字段 find({查詢條件}, {投影設置}) """
投影解釋
哪個字段 設置為 0, 此字段就不會被投影, 而其他字段全部被投影 哪個字段 設置為 1, 此字段就會被多帶帶投影, 其他字段不投影 {"name": 0, "age": 0} # 除了 name 和 age ,其他字段 都 投影 {"name": 1, "age": 1} # 只投影 name 和 age, 其他字段 不 投影,(_id除外) 注意:所有字段必須滿足如下要求: 一: 你可以不設置,默認都會被投影 二: 如果你設置了,就必須同為0,或者同為1,不允許0,1 混合設置(_id除外) 三: _id雖然可以參與混合設置,但是它只可以設為0, 不可以設為1,因為1是它默認的 通俗理解(0和1的設定):另一種理解思想 ====> 設置為1: 就是 加入 白名單 機制 設置為0, 就是 加入 黑名單 機制 注: _id字段是 MongoDB的默認字段,它是會一直被投影的(默認白名單) 但是,當你強制指定 {"_id": 0} ,強制把 _id指定為0,他就不會被投影了(變為黑名單) 語法: M: queryset = table.find({}, {"name": 0}) P: 同上
投影-數組切片($slice)
"""針對投影時的value為數組的情況下,對此數組切片,然后再投影""" 數據條件: {"arr1": [5,6,7,8,9] } 整形參數: M: queryset = table.find({},{"arr1":{"$slice": 2}}) # 2表示前2個, -2表示后兩個 P: 同上,一模一樣,一字不差 結果: { "arr1": [5,6] } 數組參數: [skip, limit] M: queryset = table.find({},{"arr1":{"$slice": [2,3]}}) # 跳過前2個,取3個 P: 同上,一模一樣,一字不差 輸出結果 => { "arr1": {7,8,9] } 注: 這種數組參數,你可以用 skip+limit 方式理解 也可以用, python的索引+切片方式理解 (skip開始查索引(0開始數), 然后取limit個)
投影-數組過濾($elemMatch)
""" 針對投影時 的value為數組的情況下,根據指定條件 對 數組 過濾,然后再投影 注意這個過濾機制: 從前向后找,遇到一個符合條件的就立刻投影(類似 python正則的 search) """ 數據條件: {"arr1": [6,7,8,9]} M: queryset = table.find({}, {"arr1": {"$elemMatch": {"$gt":5}} }) P: 同上 輸出結果 => "arr1" : [ 6 ] 解析:(我自己總結的偽流程,可參考理解) 1. 準備投影 2. 發現數組,先處理數組,可看到數組中有 elemMatch條件 elemMatch在投影中定義為: ”你給我一個條件,我把符合條件的 數組每個元素從前向后篩選 遇到第一個符合條件的就返回, 剩下的都扔掉 (這里的返回你可以理解為 return) “ 3. 把 2 步驟 返回的數據 投影
limit()
limit: (只取前n條) M: queryset = table.find({"name":"lin"}).limit(n) # n就是取的條數 P: 同上
skip()
skip: (跳過n條,從第n+1條開始取) M: queryset = table.find({"name":"lin"}).skip(n) # 從0開始數 P: 同上 解釋一下skip這個參數n: 假如n等于2 ,就是從第三個(真實個數)開始取 => 你可以借鑒數組索引的思想 a[2]
count()
count: (統計記錄數) M: count_num = table.find({"name":"lin"}).skip(1).limit(1).count() P: count_num = table.count_documents(filter={"name":"lin"}, skip=1, limit=1) 分析: find() -> 查出 3 條數據 skip(1) -> 跳過一條,就是從第二條開始取 limit(1) -> 接著上面的來,從第二條開始取(算本身哦),取一個,實際上取的就是第二條 count() -> 3 # 也許你很驚訝,按常理來說,結果應該為 1(看下面) count(applySkipLimit=false) # 這是 API原型,這個參數默認為False applySkipLimit: 看名字你就知道這函數作用了吧 默認不寫為 False: 不應用(忽略) skip(), limit() 來統計結果 ==> 上例結果為 3 設為 True: 結合 skip(), limit() 來統計最終結果 ==> 上例結果為 1 注: 對于 count() ,Mongo 和 PyMongo都有此方法,且用法是一模一樣的。 那為什么上面PyMongo中我卻用了 count_documents() 而不是 count() ????? 答: 因為 運行 或者后 戳進PyMongo源碼可清晰看見,未來版本 count() API將要廢除。 官方建議我們用 count_documents() 它的好處是把 skip() 和 limit() 由兩個函數調用 變為 2個參數傳進去了。
sort()
sort: 排序 M: queryset = table.find({"name":"lin"}).sort({"_id": -1}) # 注意,參數是{} 對象 P: queryset = table.find({"name":"lin"}).sort( "_id", -1 ) # 注意,這是2個參數 第一個參數,代表 排序依據的字段屬性 第二個參數,代表 升/降 1 : 升序 eg: 456 -1: 降序 eg: 654 特別注意: 3連招順序(優先級要牢記) () sort -> skip -> limit (排序 - 定位 - 挑選) 無論你代碼什么順序,它都會這個順序執行 eg: queryset = table.find({"name": "lin"}).sort("_id", -1).skip(1).limit(1) 也許你會有這樣一個疑惑: 為什么 count_documents 沒有放進連招里面? 答: 你仔細想想, 統計個數,和你排不排序有關系嗎? 沒錯,一點關系都沒有。。。 sort() 和 count() 沒有聯系
數組操作符
已有數據條件: { name: ["張","李","王"] } $all: M: queryset = table.find({"name": {"$all": ["張","李"]}}) # 數組值里必須包含 張和李 P:同上,一模一樣,一字不差 $elemMatch: M: queryset = table.find({"name": {"$elemMatch": {"$eq":"張"} }}) # 數組值有張 就行 P: 同上,一模一樣,一字不差
正則
M: db.xx.find( {name: { $regex: /^a/, $options:"i" }} ) P: queryset = db.xx.find({"name": {"$regex": "LIN", "$options": "i"}}) PyMongo版的或者這樣寫-> import re e1 = re.compile(r"LIN", re.I) # 把Python的正則對象 代替 Mongo語句 queryset = db.xx.find({"name": {"$regex": re1 }})聚合
聚合表達式
字段路徑表達式:
$name # 具體字段
系統變量表達式:
$$CURRENT # 表示管道中,當前操作的文檔
反轉義表達式:
$literal: "$name" # 此處 $name 原語法被破壞,現在它只是單純的字符串
聚合管道
""" 單個管道,就像 Python中的 map等高階函數原理, 分而治之。 只不過,MongoDB善于將管道串聯而已。 .aggregate([ 里面寫管道各種操作 ]) """
$match(管道查詢)
M: queryset = table.aggregate([{"$match": {"name": "zhangsan"}}]) P: 同上
$project(管道投影)
數據條件 => [ {"id":"xxx", "name" : "zhangsan", "age" : 15 }, {"id":"xxx", "name" : "lisi", "age" : 18 }, {"id":"xxx", "name" : "wangwu", "age" : 16 } ] M: queryset = table.aggregate([{"$project": {"_id": 0,"new":"5"}}]) P: 同上 結果 => [{"new": "5"}, {"new": "5"}, {"new": "5"}] 注:"new"是在投影的時候新加的,會被投影。但是加了此新值,除了_id,其他屬性默認都不會被投影了
$skip (管道跳過,原理同前面講過skip() 略)
$limit(管道截取,原理同前面講過的limit() )
M: queryset = table.aggregate([{"$skip": 1},{"$limit":1}]) P: 同上 解釋: 一共三條文檔, skip跳過了第一條,從第二條開始取,limit取一條,所以最終取的是第二條
$sort (管道排序,同上,不解釋)
M: queryset = table.aggregate([{"$sort":{"age":1}}]) P: 同上
$unwind(管道展開數組, 相當于 數學的 分配律)
數據條件 => {"name" : "Tom", "hobby" : [ "sing", "dance" ]} path小參數: M: table.aggregate([{"$unwind":{"path": "$hobby"}}]) # 注意 path是語法關鍵詞 P: 同上 結果 => { "_id" : xx, "name" : "Tom", "hobby" : "sing" } { "_id" : xx, "name" : "Tom", "hobby" : "dance" } 形象例子: a * [b+c] => a*b + a*c includeArrayIndex小參數: M: queryset = table.aggregate([{"$unwind": { "path":"$hobby", "includeArrayIndex":"index" # 展開的同時會新增index字段記錄原索引 }}]) P: 同上 結果 => {"name" : "Tom", "hobby" : "sing", "index" : NumberLong(0) } {"name" : "Tom", "hobby" : "dance", "index" : NumberLong(1) } 注意: $unwind 上面有兩種特殊情況: 情況一: 文檔中無 hobby字段 或 hobby字段為 空數組[] 那么該文檔不參與unwind展開操作, 自然就不會顯示結果。 若想讓這種文檔也參與 unwind展開操作,那么需要追加小參數 "preserveNullAndEmptyArrays":true # 與 path同級書寫 最終結果,這種字段的文檔也會被展示出來,并且 index會被賦予一個 null值 情況二: 文檔中有 hobby字段,但是該字段的值并不是數組 那么該文檔 會 參與 unwind展開操作,并且會顯示出來, 同樣 index 會被賦予一個 null值
$lookup(使用方式一)
使用方式(一):集合關聯 ===> 我的理解是,相當于關系型數據庫的 多表查詢機制 集合 <=> 表 , 多表查詢 <=> 多集合查詢 自身集合 與 外集合 根據我們指定的 關聯字段 關聯后, 如有關聯, 則新字段的值為 [外集合的關聯文檔, 。。。], 有幾條文檔關聯,這個數組就會有幾條 廢話不多說,先重新創建兩個集合: db.user.insertOne({"name":"貓", "country": ["China","USA"]}) # 一條 db.country.insertMany([{"name":"China"}, {"name":"USA"}]) # 兩條 table = db.user # 看好,我賦值了一下,下面直接寫table就行了 M: queryset = table.aggregate([{ "$lookup": { "from": "country", # 需要連接的另外一個集合的名稱(外集合) "localField": "country", # (主集合)連接的 依據 字段 "foreignField": "name", # (外集合)連接的 依據 字段 "as": "new_field" # 最終關聯后查詢出來的數據,生成新字段,as用來起名 } }]) P: 同上 結果 => { "_id" : ObjectId("5d2a6f4dee909cc7dc316bf1"), "name" : "貓", "country" : [ "China", "USA" ], # 這行之前應該不用解釋,這就是 user集合本身的數據,沒變 "new_field" : [ # 這行是新加的字段,后面解釋 { "_id" : ObjectId("5d2a6fcbee909cc7dc316bf2"), "name" : "China" }, { "_id" : ObjectId("5d2a6fcbee909cc7dc316bf3"), "name" : "USA" } ] } 解釋: 1. new_field是我們新添加的字段 2. 因為user集合和country集合 我們給出了2個依據關聯字段 并且這兩個關聯字段 "China" 和 "USA" 的值都相等 所以最終 user集合的new_field字段中 會添加 兩條 country集合的文檔 到 [] 中 3. 如果無關聯, 那么 new_field字段中的值 為 空[]
$lookup(使用方式二):
使用方式二:不做集合的關聯,而是直接把(外集合)經過條件篩選,作為新字段放到(主集合)中。 M: queryset = table.aggregate([{ "$lookup": { "from": "country", # 外集合 "let": {"coun": "$country"}, # 使(主集合)的變量 可以放在(外集合)使用 "pipeline": [{ # 外集合的專屬管道,里面只可以用外集合的屬性 "$match": { # 因為設置了 let,所以這里面可以用主集合變量 "$expr": { # $expr使得$match里面可以使用 聚合操作 "$and": [ {"$eq": ["$name", "China"]}, # 注意,這是聚合的 $eq用法 {"$eq": ["$$coun",["China", "USA"]]} ] } } }], "as": "new_field" } }]) P: 同上 解釋: 把(外集合) pipeline里面按各種條件 查到的文檔, 作為(主集合)new_field 的值。 當然,如果不需要主集合中的屬性,可以舍棄 let 字段
$group (分組--統計種類)
用法1(分組--統計字段種類) M: queryset = table.aggregate([{"$group": {"_id": "$name"}}]) # _id是固定寫法 P: 同上 結果 => [{"_id": "老鼠"}, {"_id": "狗"}, {"_id": "貓"}] 用法2(分組--聚合) 數據條件: { "name" : "貓", "country" : [ "China", "USA" ], "age" : 18 } { "name" : "狗", "country" : "Japna" } { "name" : "老鼠", "country" : "Korea", "age" : 12 } { "name" : "貓", "country" : "Japna" } M: queryset = table.aggregate([{ "$group": { "_id": "$name", # 根據name字段分組 "type_count": {"$sum": 1}, # 統計每個分類的 個數 "ageCount": {"$sum": "$age"}, # 統計age字段的 數字和 "ageAvg": {"$avg": "$age"}, # 統計age字段的 平均值 "ageMin": {"$min": "$age"}, # 統計age字段的 最小值 "ageMax": {"$max": "$age"}, # 統計age字段的 最大值 } }]) p: 同上 結果: { "_id" : "老鼠", "type_count" : 1, "ageCount" : 12, "ageAvg" : 12, "ageMin" : 12, "ageMax" : 12 } { "_id" : "狗", "type_count" : 1, "ageCount" : 0, "ageAvg" : null, "ageMin" : null, "ageMax" : null } { "_id" : "貓", "type_count" : 2, "ageCount" : 18, "ageAvg" : 18, "ageMin" : 18, "ageMax" : 18 } 注意: 若想直接對整個集合的 做統計,而不是分組再統計 把 _id改為 null即可 { _id: "null" } # (或者隨便寫一個匹配不到的 字符串或數字都行,分不了組,就自動給你統計整個集合了)
$out (聚合操作后,將結果寫入新集合)
""" 我的理解是重定向 操作, 或者理解為 視圖 操作 寫入的集合如果存在,那么會全部覆蓋(但保留索引) 聚合過程遇到錯誤,那么會自動執行 ’回滾’操作 """ M: table.aggregate([ { "$group": {"_id": "$name"} }, { "$out": "newCollection" } ]) P: 同上 最后驗證: db.newCollection.find() ,你就會看到新集合 及其 里面的內容 聚合管道 ==> 第二個參數 table.aggregate([之前說的都是這里面的參數], 下面說這個參數) allowDiskUse: true 每個聚合管道占用內存需 < 16M, 過大就會出問題 allowDiskUse設置為true, 會將內存的 寫入到臨時文件中,減緩內存壓力。 官方文檔:write data to the _tmp subdirectory in the dbPath directory Default: /data/db on Linux and macOS, datadb on Windows 它說: 默認在 dbPath配置變量下的 子目錄_tmp下, dbPath默認為 : /data/db M: queryset = table.aggregate([{ "$group": {"_id": "$name"}}], {"allowDiskUse": true} ) P: queryset = table.aggregate([{ "$group": {"_id": "$name"}}], allowDiskUse=True, # 注意,這里語法稍有不一樣 )索引
創建索引:
單鍵索引
M: table.createIndex({"name":1}) P: table.create_index([("name",-1)]) # -1代表逆序索引,注意是元組
聯合索引
索引命中:最左匹配原則 eg 1,2,3 這三個創建聯合索引, 可命中索引為:【1,12,123】 M: table.createIndex( {"name":1}, {}, {} ) # 多個{} P: table.create_index([ ("name",-1), (), () ]) # 多個元組
多鍵索引
多鍵是針對于數組來講的,創建單鍵的字段 指定為 數組字段, 默認就會設置為多鍵索引
唯一索引 (unique)
"""注意: 如果集合中,不同文檔的字段有重復,創建唯一索引的時候會報錯""" M: table.createIndex({"name":1}, {"unique":true}) P: table.create_index([("name", 1),("counrty",1)], unique=True)
稀疏索引 (sparse)
eg: 一個集合中: 給 name創建 唯一索引 插入文檔1: 有 name字段 插入文檔2: 無 name字段 (MongoDB會在索引庫中,把沒有的字段的 索引設為 {字段:null} ) 再插入文檔3, 無name字段 --> 同樣也會把索引庫中 name設為 null 但是就在這個時候,剛要把索引庫中的 name字段設為 null的時候。。。 唯一索引告訴你:” 我這里已經有了一個,{ name:null },請你滾 ” 然后就無情的給你報錯了(重復索引字段) 那咋整啊, 別急,稀疏索引就是給你辦這事的 設置稀疏索引。 MongoDB就不會把 沒有的字段 加入到索引庫了 所以,索引庫里面就不會自動添加 {字段: null} 重新再次插入文檔3, 無name字段, 可成功插入,不存在null的重復問題了 M: table.createIndex({"name":1}, {"unique":true, "sparse":true}) P: table.create_index([("name", 1),("counrty",1)], unique=True, sparse=True)
查詢索引
M:queryset = table.getIndexes() P: queryset = table.list_indexes()
刪除索引
方式1: M: table.dropIndex("索引名") # 索引名可通過 上面查詢索引的指令查 P: table.drop_index("索引名") 方式2: M: table.dropIndexes() # 刪除全部,_id除外, 想指定刪除多個,可用列表列出 P: table.drop_indexes()
查看索引性能(是否有效)
table.上面說過的任一函數().explain() # 鏈式調用 explain,表示列出此操作的性能 eg: M: queryset = table.explain().find({"name":"貓"}) P: 同上 結果中找到: queryPlanner -> winningPlan -> inputStage -> stage # stage結果對應說明如下 COLLSCAN # 未優化,還是搜的整個集合 IXSCAN # 索引起到作用 索引對投影的優化: queryPlanner -> winningPlan -> stage # stage結果對應說明如下 FETCH # 索引 對投影 未優化 PROJECTION # 索引 對投影 起到優化作用 索引對排序的優化: 同上 stage 最好 不是 sort 按索引 正序(逆序) 取數據, 這樣就有效避免了機械排序的過程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/45195.html
摘要:不要疑惑,告訴你答案這個代表正負號的正。雖然一點技術含量沒有,但是你要懂序列也許叫可迭代對象更為合適,但是我喜歡叫序列。 數據結構 可變類型與不可變類型(重頭戲) 基操: 可變類型:[], {} # 可增刪改 查 不可變類型: int float str () # 無法增刪改, 只可查 升操: + 與...
預編譯 import re re1 = re.compile(r元字符 組成的正則規則) # 元字符下面會說 re1.方法() # 方法下邊也會說 元字符: 表示普通字符: . # 除了 外 都可以匹配的到 d # 只匹配 純數字 0-9 D # 和 d相反, 除了數字全都匹配 ...
摘要:解釋就相當于把每個序列元素的每一個單獨用一個管道函數處理,再把他們按順序組合成一個新可迭代對象注意這個管道函數只能是單參數函數,如果想傳遞多個參數怎么辦使用偏函數怕有些人看不懂,這里就不用了,而是用普通函數定義方式固定值固定值固定值固定值固 map In [25]: list(map(lambda a:a**2, [1,2,3,4])) Out[25]: [1, 4, 9, 16] 解...
摘要:多線程對于爬蟲方面也可以表現出較好的性能。計算密集型就別想多線程了,一律多進程。所以同一時刻最大的并行線程數進程數的核數這條我的個人理解很模糊,參考吧多線程多線程有種通過的那種方式,非常普遍,此處就不寫了。 GIL的理解 GIL這個話題至今也是個爭議較多的,對于不用應用場景對線程的需求也就不同,說下我聽過的優點: 1. 我沒有用過其他語言的多線程,所以無法比較什么,但是對于I/O而言,...
閱讀 2882·2021-09-28 09:36
閱讀 3608·2021-09-27 13:59
閱讀 2484·2021-08-31 09:44
閱讀 2278·2019-08-30 15:54
閱讀 2352·2019-08-30 15:44
閱讀 1180·2019-08-30 13:45
閱讀 1223·2019-08-29 18:38
閱讀 1207·2019-08-29 18:37