MongoDB介紹
MongoDB是一個基于分布式文件存儲的開源文檔數(shù)據(jù)庫。由C++語言編寫。旨在為WEB應(yīng)用提供高性能、高可用性和高伸縮數(shù)據(jù)存儲解決方案。
MongoDB優(yōu)點

MongoDB使用場景
-
數(shù)據(jù)緩存
由于性能很高,MongoDB適合作為信息基礎(chǔ)設(shè)施的緩存層。在系統(tǒng)重啟之后,由MongoDB搭建的持久化緩存層可以避免下層的數(shù)據(jù)源過載。
-
對象和json存儲
MongoDB的BSON(二進制JSON)數(shù)據(jù)格式非常適合文檔化格式的存儲及查詢,而且JSON格式存儲最接近真實對象模型,對開發(fā)者友好,方便快速開發(fā)迭代,靈活的模式讓你不在為了不斷變化的需求而去頻繁修改數(shù)據(jù)庫字段和結(jié)構(gòu)。
-
高伸縮性場景
MongoDB通過分片集群,使MongoDB服務(wù)能力易于水平擴展。
-
弱事務(wù)類型業(yè)務(wù)
MongoDB不支持多文檔事務(wù),所以像銀行系統(tǒng)這種需要大量原子性復(fù)雜事務(wù)的程序不適合使用MongoDB。(注:MongoDB 4.0將支持跨文檔的事務(wù))。

MongoDB概念
通過和關(guān)系型數(shù)據(jù)庫mysql的對照,讓我們更容易的理解MongoDB的一些概念
| 關(guān)系型數(shù)據(jù)庫(sql)概念 | MongoDB概念 | 說明 |
|---|---|---|
| database | database | 數(shù)據(jù)庫 |
| table | collection | 數(shù)據(jù)庫表/集合 |
| row | document | 數(shù)據(jù)行/文檔 |
| column | filed | 數(shù)據(jù)字段/域 |
| index | index | 索引 |

數(shù)據(jù)庫
一個MongoDB中可以建立多個數(shù)據(jù)庫。
MongoDB的默認數(shù)據(jù)庫為"db",該數(shù)據(jù)庫存儲在data目錄中
集合
集合名不能以"system."開頭
關(guān)系型數(shù)據(jù)庫中的表(table)中的每一條數(shù)據(jù)(row)的格式是事先約定好的的,而MongoDB中的集合(collection)中文檔(document)的數(shù)據(jù)格式是不固定的,也就是說我們可以將如下數(shù)據(jù)插入統(tǒng)一文檔中。
{"site":"www.wuhuan.me"}
{"site":"www.baidu.com","name":"百度"}
文檔
- 文檔中的值不僅可以是在雙引號里面的字符串,還可以是其他幾種數(shù)據(jù)類型(甚至可以是整個嵌入的文檔)
例如:在關(guān)系型數(shù)據(jù)庫中有一張students表和course表,表的結(jié)構(gòu)和數(shù)據(jù)如下:**
students表
| id | name | sex | age |
|---|---|---|---|
| 1 | 李雷 | 0 | 12 |
| 2 | 韓梅梅 | 1 | 12 |
course表
| id | course_id | course_name | score | user_id |
|---|---|---|---|---|
| 1 | 1 | 語文 | 99 | 1 |
| 2 | 2 | 數(shù)學(xué) | 100 | 1 |
| 3 | 1 | 語文 | 96 | 2 |
| 4 | 2 | 數(shù)學(xué) | 98 | 3 |
以上數(shù)據(jù)和結(jié)構(gòu)在MongoDB中可以使用內(nèi)嵌文檔來表示(一對多)的關(guān)系:
{
"_id":ObjectId("5349b4ddd2781d08c09890f3"),
"name":"李雷",
"sex":"0",
"age":"12",
"course":[{
"course_id":1,
"course_name":"語文",
"score":99,
},{
"course_id":2,
"course_name":"數(shù)學(xué)",
"score":100,
}]
}
{
"_id":ObjectId("5349b4ddd2781d08c09890f4"),
"name":"韓梅梅",
"sex":"1",
"age":"12",
"course":[{
"course_id":1,
"course_name":"語文",
"score":96,
},{
"course_id":2,
"course_name":"數(shù)學(xué)",
"score":98,
}]
}
- 文檔中的鍵/值對是有序的,文檔中的鍵是不能重復(fù),且區(qū)分大小寫。
數(shù)據(jù)類型
| 數(shù)據(jù)類型 | 描述 |
|---|---|
| String | 字符串。存儲數(shù)據(jù)常用的數(shù)據(jù)類型。在 MongoDB 中,UTF-8 編碼的字符串才是合法的。 |
| Integer | 整型數(shù)值。用于存儲數(shù)值。根據(jù)你所采用的服務(wù)器,可分為 32 位或 64 位。 |
| Boolean | 布爾值。用于存儲布爾值(真/假)。 |
| Double | 雙精度浮點值。用于存儲浮點值。 |
| Min/Max | keys 將一個值與 BSON(二進制的 JSON)元素的最低值和最高值相對比。 |
| Array | 用于將數(shù)組或列表或多個值存儲為一個鍵。 |
| Timestamp | 時間戳。記錄文檔修改或添加的具體時間。 |
| Object | 用于內(nèi)嵌文檔。 |
| Null | 用于創(chuàng)建空值。 |
| Symbol | 符號。該數(shù)據(jù)類型基本上等同于字符串類型,但不同的是,它一般用于采用特殊符號類型的語言。 |
| Date | 日期時間。用 UNIX 時間格式來存儲當前日期或時間。你可以指定自己的日期時間:創(chuàng)建 Date 對象,傳入年月日信息。 |
| Object ID | 對象 ID。用于創(chuàng)建文檔的 ID。 |
| Binary Data | 二進制數(shù)據(jù)。用于存儲二進制數(shù)據(jù)。 |
| Code | 代碼類型。用于在文檔中存儲 JavaScript 代碼。 |
| Regular expression | 正則表達式類型。用于存儲正則表達式。 |
ObjectId
MongoDB文檔必須有一個默認的_id鍵,且在一個集合里_id始終唯一。_id鍵的值可以是任何類型的,默認是個ObjectId對象,它由MongoDB數(shù)據(jù)庫自動創(chuàng)建。MongoDB使用objectId而不是使用常規(guī)做法(自增主鍵)主要原因是,在多個服務(wù)器(分布式)同步自動增加主鍵費力費時。
ObjectId由12個字節(jié)的BSON組成
前4個字節(jié)表示時間戳
接下來的3個字節(jié)是機器標識碼
緊接的兩個字節(jié)由進程id組成(PID)
最后三個字節(jié)是隨機數(shù)。
創(chuàng)建新的ObjectId
我們可以在命令行通過如下語句來創(chuàng)建一個新的ObjectId
> newId=ObjectId()
上面語句將返回一個唯一的_id
ObjectId("1249b4ddd2712d08c09890f3")
也可以使用生成的ObjectId替換MongoDB自動生成的ObjectId。
MongoDB基本使用
安裝數(shù)據(jù)庫
在windows安裝MongoDB比較簡單在官網(wǎng)MongoDB下載地址下載對應(yīng)的windows安裝包一鍵安裝就行了。
安裝完之后記得將MongoDB安裝目錄下的bin目錄加入到系統(tǒng)的環(huán)境變量中。
啟動數(shù)據(jù)庫
啟動數(shù)據(jù)庫使用mongod命令
- 方式一:普通方式啟動
> mongod --dbpath E:\MongoDB\data\db #不使用默認端口的話可以加上--port=[端口號]參數(shù)
E:\data\db為數(shù)據(jù)文件路徑
- 方式二:通過配置文件啟動
> mongod --config E:\MongoDB\mongo.conf
E:\MongoDB\mongo.conf為配置文件路徑,配置文件內(nèi)容為:
# 服務(wù)端口
port=27017
# 數(shù)據(jù)文件路徑
dbpath=E:\mongondb\data\db
# 日志文件路徑
logpath=E:\mongondb\log\mongon.log
# 打開日志輸出操作
logappend=true
# 不使用任何的驗證方式登錄
noauth=true
連接數(shù)據(jù)庫
連接數(shù)據(jù)庫使用mongo [,鏈接字符串]連接url的標準語法如下
mongodb://[username:password@]host[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
- 登錄本地默認數(shù)據(jù)庫服務(wù)器,無用戶名密碼,端口默認27017,鏈接默認的db數(shù)據(jù)庫
> mongo mongodb://localhost/db
或者
> mongo
- 使用用戶名admin、密碼123456,登錄本地端口為27017的test數(shù)據(jù)庫。
> mongo mongodb://admin:123456@localhost:27017/test
創(chuàng)建數(shù)據(jù)庫
創(chuàng)建數(shù)據(jù)庫使用use [數(shù)據(jù)庫名],例如創(chuàng)建一個test123的數(shù)據(jù)庫
> use test123
switched to db test123
> db
test123
顯示當前所有的數(shù)據(jù)庫可以使用命令show dbs
> show dbs
db 0.001GB
local 0.000GB
怎么沒有我們剛才創(chuàng)建的test123呢?那是因為數(shù)據(jù)庫中還沒有內(nèi)容,我們向test123中插入db.[集合名稱].insert(json格式的數(shù)據(jù)對象)一條數(shù)據(jù),再看看!
> show dbs
db 0.001GB
local 0.000GB
> use test123
switched to db test123
> db
test123
> db.coll.insert({"title":"not data!"})
WriteResult({ "nInserted" : 1 })
> show dbs
db 0.001GB
local 0.000GB
test123 0.000GB
查看db.[集合名稱].find()剛才添加的數(shù)據(jù)
> use test123
switched to db test123
> db.coll.find()
{ "_id" : ObjectId("5a66e39914fea5f8ff237420"), "title" : "not data!" }
使用use命令如果數(shù)據(jù)庫不存在則創(chuàng)建,存在則切換到指定的數(shù)據(jù)庫。
刪除數(shù)據(jù)庫
刪除數(shù)據(jù)庫使用db.dropDatabase()函數(shù)進行
首先查看所有的數(shù)據(jù)庫
> show dbs
db 0.001GB
local 0.000GB
test123 0.000GB
接著切換到要刪除的數(shù)據(jù)庫test123
> use test123
switched to db test123
刪除當前數(shù)據(jù)庫
> db.dropDatabase()
{ "dropped" : "test123", "ok" : 1 } #刪除成功
數(shù)據(jù)增加
數(shù)據(jù)添加方法:insert(),insertOne(),insertMany()
添加一條數(shù)據(jù)
/** insert()方法 **/
> db.person.insert({name:"張三",age:18,sex:"男"});
WriteResult({ "nInserted" : 1 })
> db.person.find() });
{ "_id" : ObjectId("5a7941c65f6d5986321c8416"), "name" : "張三", "age" : 18, "sex" : "男" }
/** insertOne()方法插入一條數(shù)據(jù) **/
> db.person.insertOne({name:"張三",age:18,sex:"男"});
{ dered:true})
"acknowledged" : true,
"insertedId" : ObjectId("5a7965855f6d5986321c8422")
}
> db.person.find()
{ "_id" : ObjectId("5a7965855f6d5986321c8422"), "name" : "張三", "age" : 18, "sex" : "男" }
>
添加多條數(shù)據(jù)
*** 方式一 把要插入的數(shù)據(jù)放在一個數(shù)組中進行批量插入***
/** insert()方法 **/
> db.person.insert( [ {name:"張三",age:18,sex:"男"}, {name:"李四",age:21,sex:"女"}, {name:"王五",age:20,sex:"男"}, {name:"趙六",age:19,sex:"女"} ],{ordered:true})
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 4,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
/** insertMany()方法 **/
> db.person.insertMany( [ {name:"張三",age:18,sex:"男"}, {name:"李四",age:21,sex:"女"}, {name:"王五",age:20,sex:"男"}, {name:"趙六",age:19,sex:"女"} ],{ordered:true})
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5a7969ec5f6d5986321c8430"),
ObjectId("5a7969ec5f6d5986321c8431"),
ObjectId("5a7969ec5f6d5986321c8432"),
ObjectId("5a7969ec5f6d5986321c8433")
]
}
多加了一個參數(shù){ordered:true}表示有序插入, 有序插入碰到異常時它會直接返回,不會繼續(xù)插入數(shù)組中其余的文檔記錄。不加此參數(shù)或者{ordered:false}為無序插入, 無序的插入會在遇到異常時繼續(xù)執(zhí)行
*** 方式二 使用bluk對象進行數(shù)據(jù)的批量添加 ***
- 第一步:初始化一個批量操作對象
var bulk = db.person.initializeUnorderedBulkOp();
- 第二步:把要添加的數(shù)據(jù)添加到bulk對象中
bulk.insert({name:"趙六",age:19,sex:"女"});
bulk.insert({name:"趙六",age:19,sex:"女"});
bulk.insert({name:"趙六",age:19,sex:"女"});
- 第三步:真正添加到數(shù)據(jù)庫的方法
bulk.execute();
插入文檔你也可以使用 db.集合名稱.save(document) 命令。如果不指定 _id 字段 save() 方法類似于 insert() 方法。如果指定 _id 字段,則會更新該 _id 的數(shù)據(jù)。
insert()方法既可以插入一個數(shù)組也可插入一個對象,insertOne()方法只能插如一個對象,insertMany()只能插入一個數(shù)組,insert()返回插入成功的記錄條數(shù),而insertOne()和insertMany()方法返回成功標志和插入成功的_objectId
數(shù)據(jù)查詢
查詢命令:find(),findOne()
findOne()方法查詢的結(jié)果已經(jīng)格式化輸出了,find()方法要想格式化輸出數(shù)據(jù)調(diào)用pertty()修飾查詢方法也能達到相同的效果。
舉例:db.person.find({age:18})
查詢年齡等于18的人的所有信息
舉例:db.person.find({age:{$gt:18}},{name:1,sex:1})
查詢db數(shù)據(jù)庫中person集合中年齡大于18的人的姓名和性別
說明:如果年齡小于18可以使用$lt操作符,第二個參數(shù){name:1,sex:1}里面表示顯示的字段,如果不想顯示某個字段那么就不用寫如果第二個參數(shù)是{name:1},那么表示只顯示姓名字段,如果整個第二個參數(shù)都不寫,那么默認顯示所有的字段
修飾查詢的方法:limit()【限制條數(shù)】,sort()【排序】,skip()【跳過】,pretty()【美化格式】
舉例:db.person.find({age:{$gt:18}},{name:1,sex:1,age:1}).sort({age:-1}).limit(3).skip(1).pretty()
查詢db數(shù)據(jù)庫中person集合中年齡大于18的人的姓名和性別,然后按照年齡降序排列,然后取排列后的數(shù)據(jù)的前三條,然后再跳過一條數(shù)據(jù)后的集合
說明:sort({age:-1})中的【-1】表示降序排列,如果升序排列寫成sort({age:1})就可以。
數(shù)據(jù)刪除
刪除方法:remove(),drop()
1、remove()和drop()方法的區(qū)別
舉例:db.person.remove({})
remove方法中傳遞一個空數(shù)對象,會刪掉db數(shù)據(jù)庫中的person集合中的所有的文檔,但是不會刪除索引
舉例:db.person.drop()
會刪除db數(shù)據(jù)庫中的person集合中的所有的文檔,并且還會刪除person集合中所有的索引。效率更高。
2、刪除匹配條件的文檔
舉例:db.person.remove({name:"張三"})
刪除db數(shù)據(jù)庫中person集合中name等于張三的所有文檔。
3、刪除一條記錄
舉例:
方法1 db.person.remove({name:"張三"},{justOne:true});
方法2 db.person.remove({name:"張三"},1);
只刪除一個匹配條件的文檔
數(shù)據(jù)修改
修改方法:update()
1、$set操作符
舉例:db.person.update({name:"張三"},{$set:{age:19}})
修改名字為張三的人的年齡為19歲,只修改一條記錄
2、$currentDate操作符的作用
舉例:db.person.update({name:"張三"},{ $set:{age:"123456"},$currentDate: { lastModified: true }})
為當前修改的文檔添加一個最后修改時間的字段
3、{multi:true}參數(shù)的作用
舉例:db.person.update({name:"張三"},{$set:{age:20},$currentDate: { lastModified: true }},{multi:true})
默認情況下只修改符合條件的一個文檔,如果多個文檔符合條件并且都要修改只需要添加第三個參數(shù){multi:true}就可以修改多個文檔了。
4、upsert選項的作用
舉例:db.person.update({name:"張三"},{name:'張三三',age:20,sex:"男"},{upsert:true})
默認情況下匹配不到更新條件的文檔,update將不做任何操作,如果添加了{upsert:true}參數(shù),在沒有找到匹配文檔的情況下,它將會插入一個新的文檔。
注意:mongondb在修改數(shù)據(jù)的時候回根據(jù)數(shù)據(jù)的類型自動修改文檔中原始的數(shù)據(jù)類型,例如一個文檔中的年齡為數(shù)字類型,你修改這個記錄的時候把年齡傳入一個字符串,那么此文檔中年齡字段的類型就變成了字符串類型。
索引
索引通常能夠極大的提高查詢的效率,就像書的目錄一樣,如果沒有索引mongodb就會去掃描集合中的每個文件并選取符合查詢條件的數(shù)據(jù),在數(shù)據(jù)量大的時候這種查詢相率很低下
使用db.集合名稱.getIndexes()獲取集合索引
> db.person.getIndexes()
[
{ //person集合的默認索引
"v" : 1, //升序排列
"key" : {
"_id" : 1 //索引列
},
"name" : "_id_", //索引名稱
"ns" : "test.person" //指定集合
}
]
創(chuàng)建索引
創(chuàng)建索引的方法:createIndex()
舉例:db.person.createIndex({"name":1})
在person集合中針對name字段創(chuàng)建一個升序排列的索引
> db.person.getIndexes()
[
{ // 默認索引
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.person"
},
{ //新創(chuàng)建的索引
"v" : 1,
"key" : {
"name" : 1
},
"name" : "name_1",
"ns" : "test.person"
}
]
刪除索引
刪除索引使用命令:dropIndex()
舉例:db.person.dropIndexes({"name":1})
> db.person.getIndexes() //查詢索引
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.person"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"name" : "name_1",
"ns" : "test.person"
}
]
> db.person.dropIndex({"name":1}) //刪除
{ "nIndexesWas" : 2, "ok" : 1 }
> db.person.getIndexes() //查詢索引
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.person"
}
]
刪除全部索引使用命令:dropIndexes()
舉例:db.person.dropIndexes()
> db.person.getIndexes() //查詢索引
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.person"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"name" : "name_1",
"ns" : "test.person"
}
]
> db.person.dropIndexes() //刪除全部索引
{
"nIndexesWas" : 2,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}
> db.person.getIndexes() //查詢索引
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.person"
}
]
刪除全部索引指的是:name為非id的索引(默認索引)
導(dǎo)出數(shù)據(jù)文件
mongodump -h IP --port 端口 -u 用戶名 -p 密碼 -d 數(shù)據(jù)庫 -o 文件存在路徑
- 如果沒有用戶誰,可以去掉-u和-p。
- 如果導(dǎo)出本機的數(shù)據(jù)庫,可以去掉-h。
- 如果是默認端口,可以去掉--port。
- 如果想導(dǎo)出所有數(shù)據(jù)庫,可以去掉-d。
導(dǎo)出全部數(shù)據(jù)數(shù)據(jù)庫
mongodump -h 127.0.0.1 -o E:\mongondb\dump
導(dǎo)入數(shù)據(jù)文件
> mongorestore -h IP --port 端口 -u 用戶名 -p 密碼 -d 數(shù)據(jù)庫 --drop 文件存在路徑
--drop參數(shù):先刪除所有的記錄,然后恢復(fù)。
導(dǎo)入全部數(shù)據(jù)庫
> mongorestore E:\mongondb\dump #數(shù)據(jù)庫的備份路徑
導(dǎo)入test123數(shù)據(jù)庫
> mongorestore -d user E:\mongondb\dump\test123 #test123這個數(shù)據(jù)庫的備份路徑