MongoDB 上手開發實踐(入門上手開發這一篇就夠了)
前言
MongoDB是一個介於 關係資料庫 和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。它支援的資料結構非常鬆散,是類似 json 的 bson 格式,因此可以儲存比較複雜的資料型別。Mongo最大的特點是它支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語言,幾乎可以實現類似關係資料庫單表查詢的絕大部分功能,而且還支援對資料建立 索引 。
也有一些其他的nosql的典型資料庫,比如redis,hbase等,然而他們之間還是有區分的。(市面上有很多不錯的資料庫,這裡就不一一列舉了)
name |
type |
mongodb |
面向文件 |
redis |
鍵值儲存 |
hbase |
列儲存 |
官網必須知道的幾個點
- 資料型別
- MongoDB CRUD Operrations 基礎增刪改查
- Aggregation 聚合操作
- 查詢調優
- 索引
123這三個點基本熟悉就代表能夠滿足平時的開發需求了,然後輔助一下資料結構設計的提升能更好的完成產品的開發;在123的基礎上疊加45基本就能覆蓋線上資料的搜尋調優了。
實踐出真知,別問直接幹它
"實體結構" person:{ name:"string", age:"int", children:"array person", parentId:"string" }
建立表(collection)
//命令列 use test db.createCollection("person")
插入資料
//插入一個爸爸 db.person.insertOne({ name:"Baba", age:Int32(1234), children:[], parentId:null }) //插入了幾個兒子 db.person.insertOne({ name:"Child1", age:Int32(234), children:[], parentId:null }) db.person.insertMany( [{ name:"Child2", age:Int32(235), children:[], parentId:null },{ name:"Child3", age:Int32(236), children:[], parentId:null } ])
建立資料OK了,但是作為一個有夢想的程式設計師,必須要再瞭解一下script,嘿嘿
//迴圈大法 for(var i=0;i<10;i++){ db.person.insertOne({ name:"robot"+i, age:Int32(Math.floor(Math.random() * 100)), children:[], parentId:null }) }
截止到上一步我們已經在資料庫test中的person表插入了幾條資料了,這裡做幾個簡單的查詢熟悉下資料查詢
//查詢全部 db.person.find({}) //查詢Baba db.person.find({name:"Baba"},{age:1}).sort({age:1}) //查詢不包含baba db.person.find({name:{$ne:"Baba"}}) //查詢年齡在(200,1000)的資料,$lte $gte中包含等於,時間的大於小於也是如此 db.person.find({age:{$lt:1000,$gt:200}},{age:1,_id:0}) //查詢name中包含robot的資料,"i"代表忽略大小寫,//就是正則 db.person.find({name:/robot/i}).skip(0*5).limit(5) //或邏輯查詢,$and為與邏輯,格式相同,而$and一般用於內嵌物件的與 db.person.find({$or:[{name:"Baba"},{name:/chi/i}]})
簡單查詢後,嘗試一下update
//將名字叫Child1的parentId修改為Baba的_id //將baba的children的arr中填充Child1的_id並且年齡+1 //注意push和addtoset的區別 var baba = db.person.findOne({name:"Baba"}); db.person.updateOne({name:"Child1"},{$set:{parentId:baba._id}}) var child1 = db.person.findOne({name:"Child1"}); db.person.updateOne({_id:baba._id},{$addToSet:{children:child1._id},$inc:{age:1}}) //重複多次執行會發現CHILDREN會出現重複資料 db.person.updateOne({_id:baba._id},{$push:{CHILDREN:child1._id}}) //查詢children中不包含指定id的資料 db.person.find({children:{$in:[child1._id]}}) //----------------------------華麗分割線---------------------------------------// //通過上面的語句會對set inc push addtoset有一定的瞭解,那就把CHILDREN中的移除吧, var baba = db.person.findOne({name:"Baba"}); var child1 = db.person.findOne({name:"Child1"}); db.person.updateOne({_id:baba._id},{$push:{"CHILDREN":new ObjectId()}}) db.person.updateOne({_id:baba._id},{$pull: {"CHILDREN":child1._id}}) db.person.updateOne({_id:baba._id},{$set:{"CHILDREN":[]}}) //檢視存在CHILDREN欄位的資料 db.person.find({CHILDREN:{$exists: true}}) //徹底刪除欄位 db.person.updateMany({},{$unset:{"CHILDREN":""}})
基本的CRUD我們已經知道了,接下來是MongoDB作為非關係型資料庫厲害的地方了,聚合(aggregate)
db.person.updateMany({name:/robot/i},{$set:{obj:[ {key:"db",value:"mongo"}, {key:"db",value:"redis"}, {key:"db",value:"hbase"} ]}}) db.person.aggregate() .match({name:/robot/i}) //query .project({nm:"$name",_id:1,age:1,obj:1}) //精簡屬性 .unwind("$obj") //一般用來切分內嵌array,做資料聚合時經常會用到 .group({ _id: "$nm", count: { $sum: 1 } }) //按照某個鍵分組聚合 .sort({"count":-1}) .limit(5) //這句比較特殊,處理內嵌陣列物件的值,$elemMatch是篩選內嵌array物件的關鍵字,該查詢匹配到的資料將會在Mongo記憶體中把內嵌array匹配到的物件置頂與array的第一個,而接下來的"obj.$.value"是將改內嵌array物件中的第一個的value修改成"mongodb" db.person.updateMany({obj:{$elemMatch: {value:"mongo"}}},{$set:{"obj.$.value":"mongodb"}}) //類關係型資料庫join db.person.aggregate( [{ $lookup: { from: "person", localField: "_id", foreignField: "parentId", as: "sons" } }])
mongodb version 4.0之後的版本新增了transaction(事務)的功能,真的可以向mysql,mssql那樣回滾了,不是像redis事務那樣的,大家可以去了解下。
查詢調優
//這裡match是讓你填篩選條件,請別搞錯 db.collection.find({"match"}).explain("executionStats") //查詢結果關鍵字含義 executionStats.executionSuccess:是否執行成功 executionStats.nReturned:滿足查詢條件的文件個數,即查詢的返回條數 executionStats.executionTimeMillis:整體執行時間 executionStats.totalKeysExamined:索引整體掃描的文件個數,和早起版本的nscanned 是一樣的 executionStats.totalDocsExamined:document掃描個數, 和早期版本中的nscannedObjects 是一樣的 executionStats.executionStages:整個winningPlan執行樹的詳細資訊,一個executionStages包含一個或者多個inputStages executionStats.executionStages.stage:這裡是FETCH去掃描對於documents,後面會專門用來解釋大部分查詢使用到的各種stage的意思 executionStats.executionStages.nReturned:由於是FETCH,所以這裡該值與executionStats.nReturned一致 executionStats.executionStages.docsExamined:與executionStats.totalDocsExamined一致executionStats.inputStage中的與上述理解方式相同 explain.executionStats.executionStages.works:被查詢執行階段所操作的“工作單元(work units)”數。 explain.executionStats.executionStages.advanced:優先返回給父stage的中間結果集中文件個數 explain.executionStats.executionStages.isEOF:查詢執行是否已經到了資料流的末尾 //stage型別的含義 COLLSCAN :全表掃描 IXSCAN:索引掃描 FETCH::根據索引去檢索指定document SHARD_MERGE:各個分片返回資料進行merge SORT:表明在記憶體中進行了排序(與前期版本的scanAndOrder:true一致) SORT_MERGE:表明在記憶體中進行了排序後再合併 LIMIT:使用limit限制返回數 SKIP:使用skip進行跳過 IDHACK:針對_id進行查詢 SHARDING_FILTER:通過mongos對分片資料進行查詢 COUNT:利用db.coll.count()之類進行count運算 COUNTSCAN:count不使用用Index進行count時的stage返回 COUNT_SCAN:count使用了Index進行count時的stage返回 SUBPLA:未使用到索引的$or查詢的stage返回 TEXT:使用全文索引進行查詢時候的stage返回
索引
索引方面直接點上方的連結吧,官方這個講的還是比較好理解的,這裡就不展開說了。相信各位小夥伴一看便知
最後,響應一下咱們大大的口號 擼起袖子加油幹,嘗試一下心裡就優普啦。謝謝大家
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!
本文版權歸作者和部落格園共有,來源網址:https://www.cnblogs.com/DanielYao/歡迎各位轉載,但是未經作者本人同意,轉載文章之後必須在文章頁面明顯位置給出作者和原文連線,否則保留追究法律責任的權利。