## 前景
隨著大數據的不斷發展,非關系型數據庫已經變得越來越重要,相關的產品也都得到了飛速發展。而其中 MongoDB 更是佼佼者,作為高性能開源文檔數據庫,MongoDB 以敏捷、可擴展和對企業應用友好而著稱,因其操作簡單、完全免費、源碼公開等特點,受到了 IT 從業人員的青睞,并被廣泛部署于實際的生產環境中。
使用 MongoDB 的公司包括:BAT、360、Foursquare、Craiglist、迪士尼、SAP、Intuit、EA 等。
## 定義
MongoDB 是一個基于分布式文件存儲的數據庫。由 C++ 語言編寫。旨在為 WEB 應用提供可擴展的高性能數據存儲解決方案。MongoDB 是一個介于關系數據庫和非關系數據庫之間的產品,是非關系數據庫當中功能最豐富,最像關系數據庫的。它支持的數據結構非常松散,是類似 JSON 的 BSON 格式,因此可以存儲比較復雜的數據類型。MongoDB 最大的特點是它支持的查詢語言非常強大,其語法有點類似于面向對象的查詢語言,幾乎可以實現類似關系數據庫單表查詢的絕大部分功能,而且還支持對數據建立索引。
## 優點
MongoDB 的特點是高性能、易部署、易使用,存儲數據非常方便。主要功能特性有:
* 面向集合存儲,易存儲對象類型的數據。
* 模式自由。
* 支持動態查詢。
* 支持完全索引,包含內部對象。
* 支持查詢。
* 支持復制和故障恢復。
* 使用高效的二進制數據存儲,包括大型對象(如視頻等)。
* 自動處理碎片,以支持云計算層次的擴展性
* 支持 JavaScript,RUBY,PYTHON,JAVA,C++,PHP 等多種語言。
* 文件存儲格式為 BSON(一種 JSON 的擴展)
## BSON
BSON 是一種類似 JSON 的二進制形式的存儲格式,簡稱 Binary JSON,它和 JSON 一樣,支持內嵌的文檔對象和數組對象,但是 BSON 有 JSON 沒有的一些數據類型,如 Date 和 BinData 類型。
后面存在 MongoDB 數據庫里面的全部都是 BSON 格式的數據。
# MongoDB 使用
對 MongoDB 數據庫操作需要其提供的內置命令來操作的。
## 基本命令
* show dbs :查看有數據的庫
* use 庫名 :若沒有則創建庫并切換,若有只切換庫
* db :顯示當前操作的庫
* db.runCommand({"dropDatabase": 1}):刪除當前數據庫,注意此處的 1 沒加雙引號
## 集合操作
* show collections :顯示庫中的集合
* db.createCollection("集合名字") : 創建集合
* db.集合名.drop() 或 db.runCommand({"drop":"集合名"}) :刪除集合
## 文檔操作
### 增加文檔
給某集合里面增加文檔,注意:
* 若集合不存在,會自動創建集合。
* 保存成功之后,系統會自動給文檔增加一個 \_id 主鍵字段,主鍵是每個文檔的唯一標識,其值不能重復,就像身份證是每個人編號是唯一的。
語法格式如下:
* db.集合名.insert(BSON 格式數據),若新增的文檔主鍵已經存在,insert 會不做操作并提示錯誤。
* db.集合名.save(BSON 格式數據),若新增的文檔主鍵已經存在,save 則更改原來的內容為新內容。
~~~
db.students.insert({"name":"xx","age":18})
?
db.students.insert({"_id":ObjectId("5c457f78034a8e64b22cd683"),"name":"xx","age":19}) // 報錯 duplicate field error collection
db.students.save({"_id":ObjectId("5c457f78034a8e64b22cd683"),"name":"xx","age":19}) // 修改
~~~
### 查詢文檔
查詢集合中的文檔,語法格式如下:
* db.集合名.find() :查詢集合中所有文檔
* db.集合名.find().pretty() :格式化查詢到的文檔
* db.集合名.findOne() ? ? :查詢集合中的第一個文檔,即插入最早那個
~~~
db.students.find()
db.students.find().pretty() ? ? ? ? ?
db.students.findOne()
~~~
### 修改文檔
修改集合中的文檔,語法格式如下:
* db.集合名.update(BSON 格式數據):注意:第一個參數查詢的條件,第二個參數是修改的內容,但主鍵是不能修改。
~~~
db.students.update({"name":"xx"}, {"age":88}) ? ? ? ? ? ? ? ? ? ? ? // 注意原來的數據只剩下 {"age":88}
db.students.update({"name":"xx"}, {$set:{"age":88}}) ? ? ? ? ? ? ? // 這里就只改原來文檔的 age 的值。 ?
db.students.update({"name":"xx"}, {$set:{"age":88}}, {multi:true}) // 默認只改先找的一條,若想改多條得設置 multi 參數為 true
~~~
### 刪除文檔
刪除集合中的文旦,語法格式如下:
* db.集合名.remove() :刪除集合中的文檔,可以指定條件
~~~
db.集合名.remove({}) ? ? ? ? ? ? ? // 刪除集合中所有的文檔
db.集合名.remove({"name":"yy"}) ? ? // 刪除指定條件 name="yy" 的文檔
~~~
## 高級查詢
* 查詢 field = value 的文檔語法:db.集合名.find({ "field" : value })
~~~
// 查詢女歌星,即查詢 sex = "女"的歌星
db.singers.find({"sex":"女"})
~~~
* 查詢 field > value 的文檔語法:db.集合名.find({ "field" :?{ $gt: value }?})
~~~
// 查詢年齡大于 53 的歌星
db.singers.find({"age": { $gt: 53 }})
~~~
* 查詢 field < value 的文檔語法:db.集合名.find({ "field" :?{ $lt: value }?})
~~~
// 查詢年齡小于 35 歲的歌星
db.singers.find({"age": { $lt: 35 }})
~~~
* 查詢 field >= value 的文檔語法:db.集合名.find({ "field" :?{ $gte: value }?})
~~~
// 查詢成績大于等于 95 的歌星
db.singers.find({"score": { $gte: 95 }})
~~~
* 查詢 field <= value 的文檔語法:db.集合名.find({ "field" :?{ $lte: value }?})
~~~
// 查詢年齡在小于等于 32 歲的歌星。
db.singers.find({"age": { $lte: 32 }})
~~~
* 查詢 min < field < max 的文檔語法:db.集合名.find({ "field" :?{ lt: max?}?})
~~~
// 查詢年齡在 (30, 40) 歲之間的歌星
db.singers.find({"age": { $gt: 30 , $lt: 40 }})
~~~
* 查詢 field != value 的文檔語法:db.集合名.find({ "field" :?{?$ne: value }?})
~~~
// 查詢外國歌手
db.singers.find({"country": { $ne: "中國" }})
~~~
* 查詢 field % divisor == remainder 的文檔語法:db.集合名.find({ "field"?: { $mod : \[ divisor, remainder \] } })
~~~
// 查詢成績為 5,15,25...95 的歌星。
db.singers.find({"score" : { $mod : [10, 5] }})
~~~
* 查詢 field = value1 OR field = value2 ... OR field = valueN OR 的文檔語法:db.集合名.{ field: { $in: \[value1, value2, ... valueN \] } }
~~~
// 查詢序號(num)為 3 或者 6 或者 9 的歌星
db.singers.find({ "num" : { $in: ["3", "6", "9"] } })
~~~
* 查詢 field value2 ... AND field <> valueN 的文檔語法:db.集合名.{ field: { $nin: \[value1, value2, ... valueN \] } }
~~~
// 查詢國籍不為美國和韓國的歌手
db.singers.find({"country" : { $nin: ["美國", "韓國"] }})
~~~
* 查詢文檔字段數量的語法:db.集合名.find({ "field" :?{ $size: num }?}),注意 field 的值是數組。
~~~
// 查詢有 3 個代表作品的歌手
db.singers.find({"works" : { $size: 3 }})
~~~
* 查詢存在或不存在某個字段的的文檔語法:db.集合名.find({ "field"?: { $exists : true|false } })
~~~
// 查詢包含 name 字段的歌手
db.singers.find({"name" : { $exists : true }})
~~~
* 查詢多個條件是或的關系的文檔語法:db.集合名.find({ $or : \[expression1, expression2, ..., expressionN\] })
~~~
// 查詢名詞是劉德華的歌手或者是女歌手
db.singers.find({$or : [{"name":"劉德華"}, {"sex":"女"}]})
~~~
* 查詢多個條件是且的關系的文檔語法:db.集合名.find({ $and : \[expression1, expression2, ..., expressionN\] })
~~~
// 查詢名字是劉德華且是女的歌手
db.singers.find({$and : [{"name":"劉德華"}, {"sex":"女"}]})
~~~
* 若字段的值是對象的查詢
~~~
db.students.insert({"name":"zs", "score":{"yw":80, "sx":91}})
db.students.insert({"name":"ls", "score":{"yw":77, "sx":95}})
// 查詢語文成績為 80 的同學
db.students.find({"score.yw": 80})
~~~
* 排序查詢文檔,語法格式:db.集合名.find().sort({ "field" : -1 | 1}),注意 1 代表升序,-1 代表降序
~~~
// 對所有歌星安年齡排序
db.singers.find().sort({"age": 1})
~~~
* 限制查詢的個數,語法格式:db.集合名.find().limit(n)
~~~
// 實現輸出 5 條
db.singers.find().limit(5)
~~~
* 跳過多少條再查詢,語法格式:db.集合名.find().skip(n)
~~~
// 跳過 5 條查詢
db.list.find().skip(5)
~~~
* 分頁查詢:語法格式:db.集合名.find().skip(n).limit(n)
```
// 假如 101 條數據,每頁顯示 10 條,一共分 11 頁,那么要查詢第 2 頁的文檔
// var pageSize = 10;
// var start = (2 - 1) * pageSize;
db.list.find().skip(start).limit(pagesize)
```