1. 程式人生 > >MongoDB 上手開發實踐(入門上手開發這一篇就夠了)

MongoDB 上手開發實踐(入門上手開發這一篇就夠了)

前言

  MongoDB是一個介於 關係資料庫 和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。它支援的資料結構非常鬆散,是類似 json 的 bson 格式,因此可以儲存比較複雜的資料型別。Mongo最大的特點是它支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語言,幾乎可以實現類似關係資料庫單表查詢的絕大部分功能,而且還支援對資料建立 索引 。

也有一些其他的nosql的典型資料庫,比如redis,hbase等,然而他們之間還是有區分的。(市面上有很多不錯的資料庫,這裡就不一一列舉了)

name

type

mongodb

面向文件

redis

鍵值儲存

hbase

列儲存

 

 

官網必須知道的幾個點
  1. 資料型別
  2. MongoDB CRUD Operrations 基礎增刪改查
  3. Aggregation 聚合操作
  4. 查詢調優
  5. 索引

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/歡迎各位轉載,但是未經作者本人同意,轉載文章之後必須在文章頁面明顯位置給出作者和原文連線,否則保留追究法律責任的權利。