最后更新時間:2017-07-13 11:10:49
原始文章鏈接:http://www.lovebxm.com/2017/07/13/mongodb_primer/
MongoDB - 簡介
官網(wǎng):https://www.mongodb.com/
MongoDB 是一個基于分布式文件存儲的數(shù)據(jù)庫,由 C++ 語言編寫,旨在為 WEB 應用提供可擴展的高性能數(shù)據(jù)存儲解決方案。
MongoDB 是一個介于關系數(shù)據(jù)庫和非關系數(shù)據(jù)庫之間的產(chǎn)品,是非關系數(shù)據(jù)庫當中功能最豐富,最像關系數(shù)據(jù)庫的。

MongoDB - 安裝及運行
- 下載
07/05/2017 Current Stable Release (3.4.6)
https://www.mongodb.com/download-center#community
- 創(chuàng)建數(shù)據(jù)目錄
MongoDB 將數(shù)據(jù)目錄存儲在 db 目錄下,需手動創(chuàng)建。
E:\MongoDB\data\db
- 運行 MongoDB 服務器
為了從命令提示符下運行MongoDB服務器,你必須從MongoDB\bin目錄中執(zhí)行mongod.exe文件,不要關閉服務。ctrl + c關閉。
mongod.exe --dbpath E:\MongoDB\data\db
- MongoDB 后臺管理
運行 mongo.exe
MongoDB Shell是MongoDB自帶的交互式Javascript shell,用來對MongoDB進行操作和管理的交互式環(huán)境。
- 將 MongoDB 服務器作為 Windows 服務運行
添加系統(tǒng)環(huán)境 path E:\MongoDB\Server\3.4\bin
檢測:cmd 中輸入 mongod --help
新建文件:E:\MongoDB\logs\logs.log
將 MongoDB 服務器作為 Windows 服務隨 Windows 啟動而開啟:
mongod.exe --logpath "E:\MongoDB\logs\logs.log" --logappend --dbpath "E:\MongoDB\data" --directoryperdb --serviceName MongoDB --install
開啟 MongoDB 服務:net start MongoDB
停止 MongoDB 服務:net stop MongoDB
刪除 MongoDB 服務:sc delete MongoDB
接下來就可以在 cmd 中運行 E:\MongoDB\Server\3.4\bin 里面的 *.exe 程序了
- shell 控制臺
mongo - 數(shù)據(jù)庫的還原
mongorestore - 備份
mongodump
- mongodb 啟動的參數(shù)

mongoDB - 主要特點
- MongoDB安裝簡單。
- MongoDB的提供了一個面向文檔存儲,沒有表結構的概念,每天記錄可以有完全不同的結構,操作起來比較簡單和容易。
- 完全的索引支持(單鍵索引、數(shù)組索引、全文索引、地理位置索引 等)
- 你可以通過本地或者網(wǎng)絡創(chuàng)建數(shù)據(jù)鏡像,這使得MongoDB有更強的擴展性。
- 如果負載的增加(需要更多的存儲空間和更強的處理能力) ,它可以分布在計算機網(wǎng)絡中的其他節(jié)點上這就是所謂的分片。
- Mongo支持豐富的查詢表達式。查詢指令使用JSON形式的標記,可輕易查詢文檔中內嵌的對象及數(shù)組。
- MongoDb 使用update()命令可以實現(xiàn)替換完成的文檔(數(shù)據(jù))或者一些指定的數(shù)據(jù)字段 。
- Mongodb中的Map/reduce主要是用來對數(shù)據(jù)進行批量處理和聚合操作。
- Map和Reduce。Map函數(shù)調用emit(key,value)遍歷集合中所有的記錄,將key與value傳給Reduce函數(shù)進行處理。
- Map函數(shù)和Reduce函數(shù)是使用Javascript編寫的,并可以通過db.runCommand或mapreduce命令來執(zhí)行MapReduce操作。
- GridFS是MongoDB中的一個內置功能,可以用于存放大量小文件。
- MongoDB允許在服務端執(zhí)行腳本,可以用Javascript編寫某個函數(shù),直接在服務端執(zhí)行,也可以把函數(shù)的定義存儲在服務端,下次直接調用即可。
- MongoDB 支持多種編程語言:C C++ C# .NET Erlang Haskell Java JavaScript Lisp node.JS Perl PHP Python Ruby Scala 等
mongoDB - 工具
監(jiān)控
- Munin:網(wǎng)絡和系統(tǒng)監(jiān)控工具
- Gangila:網(wǎng)絡和系統(tǒng)監(jiān)控工具
- Cacti:用于查看CPU負載, 網(wǎng)絡帶寬利用率,它也提供了一個應用于監(jiān)控 MongoDB 的插件。
GUI
- Robomongo(Robo 3T)
- Fang of Mongo – 網(wǎng)頁式,由Django和jQuery所構成。
- Futon4Mongo – 一個CouchDB Futon web的mongodb山寨版。
- Mongo3 – Ruby寫成。
- MongoHub – 適用于OSX的應用程序。
- Opricot – 一個基于瀏覽器的MongoDB控制臺, 由PHP撰寫而成。
- Database Master — Windows的mongodb管理工具
- RockMongo — 最好的PHP語言的MongoDB管理工具,輕量級, 支持多國語言.
mongoDB - 三大重要概念

1. database 數(shù)據(jù)庫
多個集合邏輯上組織在一起,就是數(shù)據(jù)庫。
數(shù)據(jù)庫命名規(guī)范:
- 不能是空字符串("")。
- 不得含有' '(空格)、.、$、/、\和\0 (空字符)。
- 應全部小寫。
- 最多64字節(jié)。
有一些數(shù)據(jù)庫名是保留的,可以直接訪問這些有特殊作用的數(shù)據(jù)庫。
- admin: 從權限的角度來看,這是"root"數(shù)據(jù)庫。要是將一個用戶添加到這個數(shù)據(jù)庫,這個用戶自動繼承所有數(shù)據(jù)庫的權限。一些特定的服務器端命令也只能從這個數(shù)據(jù)庫運行,比如列出所有的數(shù)據(jù)庫或者關閉服務器。
- local: 這個數(shù)據(jù)永遠不會被復制,可以用來存儲限于本地單臺服務器的任意集合
- config: 當Mongo用于分片設置時,config數(shù)據(jù)庫在內部使用,用于保存分片的相關信息。
2. collection 集合
多個文檔組成一個集合,相當于關系數(shù)據(jù)庫的表。
所有存儲在集合中的數(shù)據(jù)都是 BSON 格式,BSON 是類 JSON 的一種二進制形式的存儲格式,簡稱 Binary JSON。
集合名命名規(guī)范:
- 集合名不能是空字符串""。
- 集合名不能含有\(zhòng)0字符(空字符),這個字符表示集合名的結尾。
- 集合名不能以"system."開頭,這是為系統(tǒng)集合保留的前綴。
- 用戶創(chuàng)建的集合名字不能含有保留字符。有些驅動程序的確支持在集合名里面包含,這是因為某些系統(tǒng)生成的集合中包含該字符。除非你要訪問這種系統(tǒng)創(chuàng)建的集合,否則千萬不要在名字里出現(xiàn)$。

3. document 文檔
MongoDB 將數(shù)據(jù)存儲為一個文檔,數(shù)據(jù)結構由鍵值對組成。
MongoDB 文檔是一組鍵值對(即BSON,二進制的 JSON),類似于 JSON 對象。字段值可以包含其他文檔,數(shù)組及文檔數(shù)組。
文檔鍵命名規(guī)范:
- 鍵不能含有\(zhòng)0 (空字符)。這個字符用來表示鍵的結尾。
- .和$有特別的意義,只有在特定環(huán)境下才能使用。
- 以下劃線"_"開頭的鍵是保留的(不是嚴格要求的)。
需要注意的是:
- 文檔中的鍵值對是有序的。
- 文檔中的值不僅可以是在雙引號里面的字符串,還可以是其他幾種數(shù)據(jù)類型(甚至可以是整個嵌入的文檔)。
- MongoDB區(qū)分類型和大小寫。
- MongoDB的文檔不能有重復的鍵。
- 文檔的鍵是字符串。除了少數(shù)例外情況,鍵可以使用任意UTF-8字符。


MongoDB - 數(shù)據(jù)類型
ObjectId:主鍵,一種特殊而且非常重要的類型,每個文檔都會默認配置這個屬性,屬性名為_id,除非自己定義,方可覆蓋

MongoDB - 常見操作
查看當前數(shù)據(jù)庫
db
查看所有數(shù)據(jù)庫
沒有數(shù)據(jù)的數(shù)據(jù)庫不予顯示
MongoDB 中默認的數(shù)據(jù)庫為 test,如果你沒有創(chuàng)建新的數(shù)據(jù)庫,集合將存放在 test 數(shù)據(jù)庫中。
show dbs
連接到指定的數(shù)據(jù)庫
如果數(shù)據(jù)庫不存在,則創(chuàng)建數(shù)據(jù)庫,否則切換到指定數(shù)據(jù)庫。
use db_name
查看服務器狀態(tài)
db.serverStatus()
查看數(shù)據(jù)庫統(tǒng)計信息
db.stats()
刪除數(shù)據(jù)庫
db.dropDatabase()
查看數(shù)據(jù)庫中所有集合
show tables
或
show collections
清空集合
刪除里面的文檔,但集合還在
db.col_name.remove({})
刪除集合
db.col_name.drop()
查看集合詳細信息
MongoDB 的3.0后的版本分了三種模式 queryPlanner、executionStats、allPlansExecution
db.col_name.find({key:value}).explain("allPlansExecution")
MongoDB - 增刪改查
插入
MongoDB 使用 insert() 或 save() 方法向集合中插入文檔:
如果該集合不在該數(shù)據(jù)庫中, MongoDB 會自動創(chuàng)建該集合并插入文檔。
insert() 或 save() 方法都可以向collection里插入數(shù)據(jù),兩者區(qū)別:
- 如果不指定 _id 字段,save() 方法類似于 insert() 方法。如果指定 _id 字段,則會更新該 _id 的數(shù)據(jù)。
- 使用save函數(shù),如果原來的對象不存在,那他們都可以向collection里插入數(shù)據(jù),如果已經(jīng)存在,save會調用update更新里面的記錄,而insert則會忽略操作
- insert可以一次性插入一個列表,而不用遍歷,效率高, save則需要遍歷列表,一個個插入。
db.col_name.insert(document)
db.col_name.save(document)
插入一個文檔到 col 集合中:
db.col_1.insert({
title: 'MongoDB 教程',
description: 'MongoDB 是一個 Nosql 數(shù)據(jù)庫',
by: '菜鳥教程',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
也可以將文檔數(shù)據(jù)定義為一個變量,如下所示:
document = ({
title: 'MongoDB 教程',
description: 'MongoDB 是一個 Nosql 數(shù)據(jù)庫',
by: '菜鳥教程',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
});
db.col_2.insert(document)
刪除
remove() 函數(shù)是用來刪除集合中的數(shù)據(jù)
在執(zhí)行 remove() 函數(shù)前先執(zhí)行 find() 命令來判斷執(zhí)行的條件是否正確,這是一個比較好的習慣。
db.col_name.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
- query :(可選)刪除的文檔的條件。
- justOne : (可選)如果設為 true 或 1,則只刪除一個文檔。
- writeConcern :(可選)拋出異常的級別。
刪除集合中所有文檔
db.col.remove({})
移除 col_1 集合中 title 為 MongoDB save 的文檔,只刪除第一條找到的記錄
db.col_1.remove({'title':'MongoDB save'}, 1)
更新
MongoDB 使用 update() 和 save() 方法來更新集合中的文檔
update() 方法用于更新已存在的文檔
db.col_name.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
- query : update 的查詢條件,類似sql update查詢內where后面的。
- update : update的對象和一些更新的操作符(如$,$inc...)等,也可以理解為sql update查詢內set后面的
- upsert : 可選,這個參數(shù)的意思是,如果不存在 update 的記錄,是否插入記錄,true 為插入,默認是 false,不插入。
- multi : 可選,mongodb 默認是false,只更新找到的第一條記錄,如果這個參數(shù)為true,就把按條件查出來多條記錄全部更新。
- writeConcern :可選,拋出異常的級別。
通過 update() 方法來更新 col_1 集合中的 title
$set 操作符為部分更新操作符,只更新 $set 之后的數(shù)據(jù),而不是覆蓋之前的數(shù)據(jù)
db.col_1.update({ 'title': 'MongoDB 教程' }, { $set: { 'title': 'MongoDB' } })
以上語句只會修改第一條發(fā)現(xiàn)的文檔,如果要修改多條相同的文檔,則需要設置 multi 參數(shù)為 true。
db.col_1.update({ 'title': 'MongoDB 教程' }, { $set: { 'title': 'MongoDB' } }, { multi: true })
save() 方法通過傳入的文檔來替換已有文檔。語法格式如下:
db.col_name.save(
<document>,
{
writeConcern: <document>
}
)
以下實例中我們替換了 col_1 的文檔數(shù)據(jù):
document = ({
"_id": "1",
"title": "MongoDB save",
"description": "MongoDB 是一個 Nosql 數(shù)據(jù)庫",
"by": "菜鳥",
"url": "http://www.runoob.com",
"tags": ["mongodb", "database", "NoSQL"],
});
db.col_1.save(document)
查詢
find() 方法,它返回集合中所有文檔。
findOne() 方法,它只返回一個文檔。
db.col_name.find(query, projection)
- query :可選,使用查詢操作符指定查詢條件
- projection :可選,使用投影操作符指定返回的鍵。查詢時返回文檔中所有鍵值, 只需省略該參數(shù)即可(默認省略)。
格式化輸出:
db.col_name.find().pretty()
查看集合中文檔的個數(shù):
db.col_name.find().count()
跳過指定數(shù)量的數(shù)據(jù):
db.col_name.find().skip()
讀取指定記錄的條數(shù):
db.col_name.find().limit()
排序:
sort()方法可以通過參數(shù)指定排序的字段,并使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而-1是用于降序排列。
db.col_name.find().sort({key:1})
sort()方法可以通過參數(shù)指定排序的字段,并使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而-1是用于降序排列。
Where 語句
如果你想獲取"col"集合中 "likes" 大于100,小于 200 的數(shù)據(jù),你可以使用以下命令:
db.col.find({likes : {$lt :200, $gt : 100}})
// 類似于SQL語句:
Select * from col where likes>100 AND likes<200;
| 條件操作符 | 中文 | 全英文 |
|---|---|---|
| $gt | 大于 | greater than |
| $gte | 大于等于 | greater than equal |
| $lt | 小于 | less than |
| $lte | 小于等于 | less than equal |
| $ne | 不等于 | not equal |

$type 操作符
用來檢索集合中匹配的數(shù)據(jù)類型

如果想獲取 "col" 集合中 title 為 String 的數(shù)據(jù),你可以使用以下命令:
db.col.find({"title" : {$type : 2}})
AND 條件
find() 方法可以傳入多個鍵(key),每個鍵(key)以逗號隔開,語法格式如下:
db.col_name.find({key1:value1, key2:value2}).pretty()
// 類似于 SQL and 語句:
SELECT * FROM col_name WHERE key1='value1' AND key2=value2
OR 條件
db.col_name.find({ $or: [{ "by": "菜鳥教程" }, { "title": "MongoDB 教程" }] }).pretty()
// 類似于 SQL or 語句:
SELECT * FROM col_name WHERE key1=value1 OR key2=value2
AND 和 OR 聯(lián)合使用
db.col_name.find({
"likes": {
$gt: 50
},
$or: [{
"by": "菜鳥教程"
}, {
"title": "MongoDB 教程"
}]
}).pretty()
// 類似常規(guī) SQL 語句:
SELECT * FROM col_name where likes>50 AND (by = '菜鳥教程' OR title = 'MongoDB 教程')
MongoDB - 索引
注意:從 mongoDB 3.0 開始,ensureIndex 被廢棄,今后都僅僅是 createIndex 的一個別名。
索引通常能夠極大的==提高查詢的效率==,如果沒有索引,MongoDB在讀取數(shù)據(jù)時必須掃描集合中的每個文件并選取那些符合查詢條件的記錄。
這種掃描全集合的查詢效率是非常低的,特別在處理大量的數(shù)據(jù)時,查詢可以要花費幾十秒甚至幾分鐘,這對網(wǎng)站的性能是非常致命的。
索引是特殊的數(shù)據(jù)結構,索引存儲在一個易于遍歷讀取的數(shù)據(jù)集合中,索引是對數(shù)據(jù)庫表中一列或多列的值進行排序的一種結構
索引常用命令
getIndexes 查看集合索引情況
db.col_name.getIndexes()
hint 強制使用索引
db.col_name.find({age:{$lt:30}}).hint({name:1, age:1}).explain()
刪除索引(不會刪除 _id 索引)
db.col_name.dropIndexes()
db.col_name.dropIndex({firstname: 1})
createIndex() 方法
MongoDB使用 createIndex() 方法來創(chuàng)建索引
key 為你要創(chuàng)建的索引字段,1為按升序創(chuàng)建索引,-1為按降序創(chuàng)建索引。
也可以設置使用多個字段創(chuàng)建索引(關系型數(shù)據(jù)庫中稱作復合索引)
db.col_name.createIndex({key:1})
createIndex() 接收可選參數(shù),可選參數(shù)列表如下:

_id 索引
對于每個插入的數(shù)據(jù),都會自動生成一條唯一的 _id 字段,_id 索引是絕大多數(shù)集合默認建立的索引
> db.col_1.insert({x:10})
WriteResult({ "nInserted" : 1 })
> db.col_1.find()
{ "_id" : ObjectId("59658e56aaf42d1c98dd95a2"), "x" : 10 }
> db.col_1.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "runoob.col_1"
}
]
字段解釋:
v 表示 version,在 Mongo3.2 之前的版本中,會存在 {v:0}(版本鎖為0)的情況。在3.2之后的版本中,{v:0} 不再允許使用,這部分可以不去關注,因為 v 由系統(tǒng)自動管理
key 表示作為索引的鍵。1 或 -1表示排序模式,1為升序,1為降序
name 表示索引的名字,默認生成名稱的規(guī)則是作為
索引的字段_排序模式ns 表示 namespace 命名空間,由
數(shù)據(jù)庫名稱.集合名稱組成
單鍵索引
最普通的索引,不會自動創(chuàng)建
// 對 x 字段創(chuàng)建升序索引
> db.col_1.createIndex({x:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.col_1.find()
{ "_id" : ObjectId("59658e56aaf42d1c98dd95a2"), "x" : 10 }
> db.col_1.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "runoob.col_1"
},
{
"v" : 2,
"key" : {
"x" : 1
},
"name" : "x_1",
"ns" : "runoob.col_1"
}
]
多鍵索引
單鍵索引的值為一個單一的值,多鍵索引的值有多個數(shù)據(jù)(如數(shù)組)
如果mongoDB中插入數(shù)組類型的多鍵數(shù)據(jù),索引是自動建立的,無需刻意指定
> db.col_1.insert({z:[1,2,3,4,5]})
WriteResult({ "nInserted" : 1 })
> db.col_1.find()
{ "_id" : ObjectId("59658e56aaf42d1c98dd95a2"), "x" : 10 }
{ "_id" : ObjectId("5965923eaaf42d1c98dd95a3"), "y" : 20 }
{ "_id" : ObjectId("59659828aaf42d1c98dd95a4"), "z" : [ 1, 2, 3, 4, 5 ] }
> db.col_1.find({z:3})
{ "_id" : ObjectId("59659828aaf42d1c98dd95a4"), "z" : [ 1, 2, 3, 4, 5 ] }
復合索引
同時對多個字段創(chuàng)建索引
> db.col_2.insert({x:10,y:20,z:30})
WriteResult({ "nInserted" : 1 })
> db.col_2.find()
{ "_id" : ObjectId("59659a57aaf42d1c98dd95a5"), "x" : 10, "y" : 20, "z" : 30 }
> db.col_2.createIndex({x:1,y:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.col_2.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "runoob.col_2"
},
{
"v" : 2,
"key" : {
"x" : 1,
"y" : 1
},
"name" : "x_1_y_1",
"ns" : "runoob.col_2"
}
]
過期索引
又稱 TTL(Time To Live,生存時間)索引,即在一段時間后會過期的索引(如登錄信息、日志等)
過期后的索引會連同文檔一起刪除
expireAfterSeconds:指定一個以秒為單位的數(shù)值,設定集合的生存時間。
注意:
- 存儲在過期索引字段的值必須是指定的時間類型(必須是 ISODate 或 ISODate 數(shù)組,不能使用時間戳,否則不能被自動刪除)
- 如果指定了 ISODate 數(shù)組,則按照最小的時間進行刪除
- 過期索引不能是復合索引(不能指定兩個過期時間)
- 刪除時間存在些許誤差(1 分鐘左右)
> db.col_3.insert({x:new Date()})
WriteResult({ "nInserted" : 1 })
> db.col_3.find()
{ "_id" : ObjectId("59659f3baaf42d1c98dd95a7"), "x" : ISODate("2017-07-12T04:02:03.835Z") }
> db.col_3.createIndex({x:1},{expireAfterSeconds:10})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.col_3.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "runoob.col_3"
},
{
"v" : 2,
"key" : {
"x" : 1
},
"name" : "x_1",
"ns" : "runoob.col_3",
"expireAfterSeconds" : 10
}
]
> db.col_3.find()
// 無返回
全文索引
場景:全網(wǎng)站關鍵詞搜索
key-value 中,key 此時為 $**(也可以是具體某 key),value 此時為一個固定的字符串(如 text)
全文索引相似度,與 sort 函數(shù)一起使用效果更好
db.col_7.find({ $text: { $search: "aa bb" } }, { score: { $meta: "textScore" } }).sort({ score: { $meta: "textScore" } })
注意:
- 每個集合只能創(chuàng)建一個全文索引
- MongoDB 從 2.4 版本開始支持全文檢索,從 3.2 版本開始支持中文
- (好像)只能對整個單詞查詢,不能對單詞的截取部分查詢
- 關鍵詞之間的空格表示
或 - 關鍵詞之前的 - 表示
非 - 關鍵詞加引號表示
與(需用 \ 轉義)
> db.col_7.find()
{ "_id" : ObjectId("5965aa84aaf42d1c98dd95b0"), "title" : "aa bb cc", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
{ "_id" : ObjectId("5965aa8faaf42d1c98dd95b1"), "title" : "abc def", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
{ "_id" : ObjectId("5965aedfaaf42d1c98dd95b2"), "title" : "aa bb", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
> db.col_7.createIndex({"title": "text"})
> db.col_7.find({$text:{$search:"aa"}})
{ "_id" : ObjectId("5965aa84aaf42d1c98dd95b0"), "title" : "aa bb cc", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
{ "_id" : ObjectId("5965aedfaaf42d1c98dd95b2"), "title" : "aa bb", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
> db.col_7.find({$text:{$search:"aa cc"}})
{ "_id" : ObjectId("5965aa84aaf42d1c98dd95b0"), "title" : "aa bb cc", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
{ "_id" : ObjectId("5965aedfaaf42d1c98dd95b2"), "title" : "aa bb", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
> db.col_7.find({$text:{$search:"\"aa\" \"cc\""}})
{ "_id" : ObjectId("5965aa84aaf42d1c98dd95b0"), "title" : "aa bb cc", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
> db.col_7.find({$text:{$search:"aa bb"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}})
{ "_id" : ObjectId("5965aedfaaf42d1c98dd95b2"), "title" : "aa bb", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》", "score" : 1.5 }
{ "_id" : ObjectId("5965aa84aaf42d1c98dd95b0"), "title" : "aa bb cc", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》", "score" : 1.3333333333333333 }
> db.col_7.dropIndexes()
> db.col_7.createIndex({"author": "text"}))
> db.col_7.find({$text:{$search:"小明"}})})
>
> db.col_7.find({$text:{$search:"白小明"}})
{ "_id" : ObjectId("5965aa84aaf42d1c98dd95b0"), "title" : "aa bb cc", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
{ "_id" : ObjectId("5965aa8faaf42d1c98dd95b1"), "title" : "abc def", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
{ "_id" : ObjectId("5965aedfaaf42d1c98dd95b2"), "title" : "aa bb", "author" : "白小明", "article" : "這是白小明的一篇文章,標題《aa bb cc》" }
地理位置索引
查看最近的點
MongoDB - 聚合
==分組計算==
MongoDB 中聚合主要用于處理數(shù)據(jù)(如平均值,求和等),并返回計算后的數(shù)據(jù)結果。類似sql語句中的 count(*)。
aggregate() 方法
db.col_name.aggregate(AGGREGATE_OPERATION)
下表展示了一些聚合的表達式:

實例
計算每個作者所寫的文章數(shù)
在下面的例子中,我們通過字段by_user字段對數(shù)據(jù)進行分組,并計算by_user字段相同值的總和。
集合中的數(shù)據(jù)如下:
{
"_id" : ObjectId("5963b992a812aa05b9d2e765"),
"title" : "MongoDB Overview",
"description" : "MongoDB is no sql database",
"by_user" : "runoob.com",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}
{
"_id" : ObjectId("5963b9aaa812aa05b9d2e766"),
"title" : "NoSQL Overview",
"description" : "No sql database is very fast",
"by_user" : "runoob.com",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 10
}
{
"_id" : ObjectId("5963b9bba812aa05b9d2e767"),
"title" : "Neo4j Overview",
"description" : "Neo4j is no sql database",
"by_user" : "Neo4j",
"url" : "http://www.neo4j.com",
"tags" : [
"neo4j",
"database",
"NoSQL"
],
"likes" : 750
}
使用aggregate()計算結果如下:
db.col_1.aggregate([{
$group: {
_id: "$by_user",
num_tutorial: {
$sum: 1
}
}
}])
// 返回
{ "_id" : "Neo4j", "num_tutorial" : 1 }
{ "_id" : "runoob.com", "num_tutorial" : 2 }
// 以上實例類似sql語句
select by_user, count(*) from col_1 group by by_user
聚合管道
管道在Unix和Linux中一般用于將當前命令的輸出結果作為下一個命令的參數(shù)。
MongoDB 的聚合管道將MongoDB文檔在一個管道處理完畢后將結果傳遞給下一個管道處理。管道操作是可以重復的。
表達式:處理輸入文檔并輸出。表達式是無狀態(tài)的,只能用于計算當前聚合管道的文檔,不能處理其它的文檔。
聚合管道常用的幾個操作:
- $project:修改輸入文檔的結構。可以用來重命名、增加或刪除域,也可以用于創(chuàng)建計算結果以及嵌套文檔。
- $match:用于過濾數(shù)據(jù),只輸出符合條件的文檔。$match使用MongoDB的標準查詢操作。
- $limit:用來限制MongoDB聚合管道返回的文檔數(shù)。
- $skip:在聚合管道中跳過指定數(shù)量的文檔,并返回余下的文檔。
- $unwind:將文檔中的某一個數(shù)組類型字段拆分成多條,每條包含數(shù)組中的一個值。
- $group:將集合中的文檔分組,可用于統(tǒng)計結果。
- $sort:將輸入文檔排序后輸出。
- $geoNear:輸出接近某一地理位置的有序文檔。
實例
$project 實例
0 為不顯示,1為顯示,默認情況下 _id 字段是 1
db.articles.aggregate({
$project: {
_id: 0,
title: 1,
by_user: 1,
}
});
// 返回
{ "title" : "MongoDB Overview", "by_user" : "runoob.com" }
{ "title" : "NoSQL Overview", "by_user" : "runoob.com" }
{ "title" : "Neo4j Overview", "by_user" : "Neo4j" }
$match 實例
$match 用于獲取分數(shù)大于70小于或等于90記錄,然后將符合條件的記錄送到下一階段$group管道操作符進行處理。
db.articles.aggregate([
{ $match: { score: { $gt: 70, $lte: 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
]);
// 返回
{ "_id" : null, "count" : 1 }
$skip 實例
經(jīng)過 $skip 管道操作符處理后,前2個文檔被"過濾"掉。
db.col_1.aggregate({ $skip: 2 });
MongoDB - 復制
MongoDB 復制(副本集)是==將數(shù)據(jù)同步在多個服務器==的過程。
復制提供了數(shù)據(jù)的冗余備份,并在多個服務器上存儲數(shù)據(jù)副本,提高了數(shù)據(jù)的可用性, 并可以保證數(shù)據(jù)的安全性。
特點:
保障數(shù)據(jù)的安全性
數(shù)據(jù)高可用性 (24*7)
災難恢復,復制允許您從硬件故障和服務中斷中恢復數(shù)據(jù)。
無需停機維護(如備份,重建索引,壓縮)
分布式讀取數(shù)據(jù)
N 個節(jié)點的集群
任何節(jié)點可作為主節(jié)點
所有寫入操作都在主節(jié)點上
自動故障轉移
自動恢復
復制原理
mongodb 的復制至少需要兩個節(jié)點。
- 其中一個是==主節(jié)點==,負責處理客戶端請求,
- 其余的都是==從節(jié)點==,負責復制主節(jié)點上的數(shù)據(jù)。
mongodb各個節(jié)點常見的搭配方式為:一主一從、一主多從。
主節(jié)點記錄在其上的所有操作oplog,從節(jié)點定期輪詢主節(jié)點獲取這些操作,然后對自己的數(shù)據(jù)副本執(zhí)行這些操作,從而保證從節(jié)點的數(shù)據(jù)與主節(jié)點一致。

復制設置
- 關閉正在運行的MongoDB服務器。
現(xiàn)在我們通過指定 --replSet 選項來啟動mongoDB
mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
實例:
下面實例會啟動一個名為rs0的MongoDB實例,其端口號為27017。
啟動后打開命令提示框并連接上mongoDB服務。
在Mongo客戶端使用命令rs.initiate()來啟動一個新的副本集。
我們可以使用rs.conf()來查看副本集的配置
查看副本集狀態(tài)使用 rs.status() 命令
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
副本集添加成員
添加副本集的成員,我們需要使用多條服務器來啟動mongo服務。
進入Mongo客戶端,并使用rs.add()方法來添加副本集的成員。
rs.add(HOST_NAME:PORT)
實例:
假設你已經(jīng)啟動了一個名為 mongod1.net,端口號為27017的Mongo服務。
在客戶端命令窗口使用rs.add() 命令將其添加到副本集中,命令如下所示:
rs.add("mongod1.net:27017")
MongoDB 中你只能通過主節(jié)點將Mongo服務添加到副本集中, 判斷當前運行的Mongo服務是否為主節(jié)點可以使用命令
db.isMaster()
MongoDB的副本集與我們常見的主從有所不同,主從在主機宕機后所有服務將停止,而副本集在主機宕機后,副本會接管主節(jié)點成為主節(jié)點,不會出現(xiàn)宕機的情況。
MongoDB - 分片
當MongoDB存儲海量的數(shù)據(jù)時,==一臺機器可能不足以存儲數(shù)據(jù)==,也可能不足以提供可接受的讀寫吞吐量。這時,我們就可以通過在多臺機器上分割數(shù)據(jù),使得數(shù)據(jù)庫系統(tǒng)能存儲和處理更多的數(shù)據(jù)。
為什么使用分片?
- 復制所有的寫入操作到主節(jié)點
- 延遲的敏感數(shù)據(jù)會在主節(jié)點查詢
- 單個副本集限制在12個節(jié)點
- 當請求量巨大時會出現(xiàn)內存不足。
- 本地磁盤不足
- 垂直擴展價格昂貴
分片集群結構

三個主要組件:
- Shard: 用于存儲實際的數(shù)據(jù)塊,實際生產(chǎn)環(huán)境中一個shard server角色可由幾臺機器組個一個replica set承擔,防止主機單點故障
- Config Server: mongod實例,存儲了整個 ClusterMetadata,其中包括 chunk信息。
- Query Routers: 前端路由,客戶端由此接入,且讓整個集群看上去像單一數(shù)據(jù)庫,前端應用可以透明使用。
MongoDB - 監(jiān)控
監(jiān)控可以了解 MongoDB 的==運行情況==及==性能==
MongoDB中提供了 mongostat 和 mongotop 兩個命令來監(jiān)控MongoDB的運行情況。
mongostat
它會間隔固定時間獲取 mongodb 的當前運行狀態(tài),并輸出。
如果你發(fā)現(xiàn)數(shù)據(jù)庫突然變慢或者有其他問題的話,你第一手的操作就考慮采用 mongostat 來查看 mongo 的狀態(tài)。
mongostat

mongotop
mongotop用來跟蹤MongoDB的實例,提供每個集合的統(tǒng)計數(shù)據(jù)。默認情況下,mongotop每一秒刷新一次。
mongotop

輸出結果字段說明:
- ns:包含數(shù)據(jù)庫命名空間,后者結合了數(shù)據(jù)庫名稱和集合。
- db:包含數(shù)據(jù)庫的名稱。名為 . 的數(shù)據(jù)庫針對全局鎖定,而非特定數(shù)據(jù)庫。
- total:mongod花費的時間工作在這個命名空間提供總額。
- read:提供了大量的時間,這mongod花費在執(zhí)行讀操作,在此命名空間。
- write:提供這個命名空間進行寫操作,這mongod花了大量的時間。
等待的時間長度,以秒為單位,默認 1s
mongotop 10
報告每個數(shù)據(jù)庫的鎖的使用
mongotop --locks
MongoDB - 備份與恢復
mongodump
在Mongodb中我們使用 mongodump 命令來備份MongoDB數(shù)據(jù)。
該命令可以導出所有數(shù)據(jù)到指定目錄中。
mongodump命令可以通過參數(shù)指定導出的數(shù)據(jù)量級轉存的服務器。
mongodump -h dbhost -d dbname -o dbdirectory
-h:MongDB所在服務器地址,例如:127.0.0.1,當然也可以指定端口號:127.0.0.1:27017
-d:需要備份的數(shù)據(jù)庫實例,例如:test
-o:備份的數(shù)據(jù)存放位置,例如:c:\data\dump,當然該目錄需要提前建立,在備份完成后,系統(tǒng)自動在dump目錄下建立一個test目錄,這個目錄里面存放該數(shù)據(jù)庫實例的備份數(shù)據(jù)。
實例
備份 mongodb_study 數(shù)據(jù)庫中的所有集合到 E:\MongoDB\dump
mongodump -h 127.0.0.1 -d mongodb_study -o E:\MongoDB\dump
不帶任何參數(shù),即在當前目錄下備份所有數(shù)據(jù)庫實例
mongodump
備份所有MongoDB數(shù)據(jù)
mongodump --host HOST_NAME --port PORT_NUMBER
// 如
mongodump --host w3cschool.cc --port 27017
備份指定數(shù)據(jù)庫的集合
mongodump --collection COLLECTION_NAME --db DB_NAME
// 如
mongodump --collection mycol --db test
mongorestore
在Mongodb中我們使用 mongorestore 命令來恢復MongoDB數(shù)據(jù)。
mongorestore -h <hostname><:port> -d dbname <path>
--host <:port>, -h <:port>:MongoDB所在服務器地址,默認為: localhost:27017
--db , -d :需要恢復的數(shù)據(jù)庫實例,例如:test,當然這個名稱也可以和備份時候的不一樣,比如test2
--drop:恢復的時候,先刪除當前數(shù)據(jù),然后恢復備份的數(shù)據(jù)。就是說,恢復后,備份后添加修改的數(shù)據(jù)都會被刪除,慎用哦!
<path>:mongorestore 最后的一個參數(shù),設置備份數(shù)據(jù)所在位置,例如:c:\data\dump\test。你不能同時指定 <path> 和 --dir 選項,--dir也可以設置備份目錄。
--dir:指定備份的目錄,你不能同時指定 <path> 和 --dir 選項。
實例
恢復存放在 E:\MongoDB\dump 中的數(shù)據(jù)庫 mongodb_study,恢復前后的數(shù)據(jù)庫名不必相同
mongorestore -h localhost /db mongodb_study /dir E:\MongoDB\dump\mongodb_study
Node.js 連接 MongoDB
與 MySQL 不同的是 MongoDB 會自動創(chuàng)建數(shù)據(jù)庫和集合,所以使用前我們不需要手動去創(chuàng)建。
安裝驅動:npm install mongodb
運行 node:node connect
實例
connect.js
const MongoClient = require('mongodb').MongoClient;
// 自動創(chuàng)建數(shù)據(jù)庫 runoob
let mongoConnect = 'mongodb://localhost:27017/runoob';
// 插入數(shù)據(jù),插入到數(shù)據(jù)庫 runoob 的 site 集合中
let insertData = function(db, callback) {
// 自動創(chuàng)建集合 site
let collection = db.collection('site');
// 插入文檔
let data = [{
"name": "菜鳥教程",
"url": "www.runoob.com"
}, {
"name": "菜鳥工具",
"url": "c.runoob.com"
}];
collection.insert(data, function(err, result) {
if (err) {
console.log('Error:' + err);
return;
}
callback(result);
});
};
// 刪除數(shù)據(jù),刪除所有 name 為 "菜鳥工具" 的文檔
let deleteData = function(db, callback) {
let collection = db.collection('site');
let whereStr = {
"name": "菜鳥工具"
};
collection.remove(whereStr, function(err, result) {
if (err) {
console.log('Error:' + err);
return;
}
callback(result);
});
};
// 修改數(shù)據(jù),將所以 name 為 "菜鳥教程" 的 url 改為 https://www.runoob.com
let updateData = function(db, callback) {
let collection = db.collection('site');
let whereStr = {
"name": "菜鳥教程"
};
let updateStr = {
$set: {
"url": "https://www.runoob.com"
}
};
collection.update(whereStr, updateStr, {
multi: true
}, function(err, result) {
if (err) {
console.log('Error:' + err);
return;
}
callback(result);
});
};
// 查詢數(shù)據(jù),查詢 name 為 "菜鳥教程" 的數(shù)據(jù)
let selectData = function(db, callback) {
let collection = db.collection('site');
let whereStr = {
"name": '菜鳥教程'
};
collection.find(whereStr).toArray(function(err, result) {
if (err) {
console.log('Error:' + err);
return;
}
callback(result);
});
};
MongoClient.connect(mongoConnect, function(err, db) {
console.log("連接成功!");
insertData(db, function(result) {
console.log("插入數(shù)據(jù)成功!");
console.log(result);
db.close();
});
deleteData(db, function(result) {
console.log("刪除數(shù)據(jù)成功!");
console.log(result);
db.close();
});
updateData(db, function(result) {
console.log("修改數(shù)據(jù)成功!");
console.log(result);
db.close();
});
selectData(db, function(result) {
console.log("查詢數(shù)據(jù)成功!");
console.log(result);
db.close();
});
});
mongoose
Mongoose學習參考文檔——基礎篇:https://cnodejs.org/topic/504b4924e2b84515770103dd
mongoose學習筆記:https://cnodejs.org/topic/58b911997872ea0864fee313
mongoose學習文檔:http://www.cnblogs.com/y-yxh/p/5689555.html
Nodejs學習筆記(十四)— Mongoose介紹和入門:http://www.cnblogs.com/zhongweiv/p/mongoose.html
Mongoose全面理解:http://www.cnblogs.com/jayruan/p/5123754.html
Node.js 有針對 MongoDB 的數(shù)據(jù)庫驅動:mongodb。你可以使用 npm install mongodb 來安裝。不過直接使用 mongodb 模塊雖然強大而靈活,但有些繁瑣,我就使用 mongoose 吧。
Mongoose 基于nodejs、構建在 mongodb 之上,使用 javascript 編程,是==連接 mongodb 數(shù)據(jù)庫的軟件包==,使mongodb的文檔數(shù)據(jù)模型變的優(yōu)雅起來,方便對mongodb文檔型數(shù)據(jù)庫的連接和增刪改查等常規(guī)數(shù)據(jù)操作。
mongoose 是當前使用 mean(mongodb express angularjs nodejs)全棧開發(fā)必用的連接數(shù)據(jù)庫軟件包。
==mongoose ,提供了Schema、Model 和 Document 對象,用起來更為方便。== 另外,mongoose 還有 Query 和 Aggregate 對象:Query 實現(xiàn)查詢、Aggregate 實現(xiàn)聚合
mongoose 三個重要概念

Schema、Model、Entity 的關系:Schema生成Model,Model創(chuàng)造Entity,Model和Entity都可對數(shù)據(jù)庫操作造成影響,但Model比Entity更具操作性。
1. Schema 模式
Schema 對象定義==文檔結構==,可以定義字段、類型、唯一性、索引、驗證等。
Schema 不僅定義了文檔結構和使用性能,還可以有擴展插件、實例方法、靜態(tài)方法、復合索引、文檔生命周期鉤子
// new mongoose.Schema() 中傳入一個 JSON 對象,定義屬性和屬性類型
var BlogSchema = new mongoose.Schema({
title: String,
author: String
});
有的時候,我們創(chuàng)造的 Schema 不僅要為后面的 Model 和 Entity 提供公共的屬性,還要提供公共的方法。
2. Model 模型
Model 對象表示集合中的所有文檔
由 Schema 發(fā)布生成的模型,具有抽象屬性和行為的數(shù)據(jù)庫操作對
3. Document 文檔
Document 可等同于 Entity
由 Model 創(chuàng)建的實體,他的操作也會影響數(shù)據(jù)庫
使用
- 定義一個 Schema 模式
- 將該 Schema 發(fā)布為 Model
- 用 Model 創(chuàng)建 Entity
- Entity 是具有具體的數(shù)據(jù)庫操作 CRUD 的
mongoose 的 connection 對象定義了一些事件,比如 connected open close error 等,我們可以監(jiān)聽這些事件。
const mongoose = require('mongoose');
let db = mongoose.connect('mongodb://127.0.0.1:27017/test');
db.connection.on('error', console.error.bind(console, '數(shù)據(jù)庫連接失?。?));
db.connection.once('open', function() {
console.log('數(shù)據(jù)庫連接成功!');
// 定義一個 Schema 模式
// new Schema() 中傳入一個 JSON 對象,定義屬性和屬性類型
let PersonSchema = new mongoose.Schema({
name: {
type: String,
unique: true
},
password: String
});
// 將該 Schema 發(fā)布為 Model
let PersonModel = mongoose.model('col_1', PersonSchema);
// 拿到了 Model 對象,就可以執(zhí)行增刪改查等操作了
// 如果要執(zhí)行查詢,需要依賴 Model,當然 Entity 也是可以做到的
PersonModel.find(function(err, result) {
// 查詢到的所有person
});
// 用 Model 創(chuàng)建 Entity
let personEntity = new PersonModel({
name: 'Krouky',
password: '10086'
});
// Entity 是具有具體的數(shù)據(jù)庫操作 CRUD 的
// 執(zhí)行完成后,數(shù)據(jù)庫就有該數(shù)據(jù)了
personEntity.save(function(err, result) {
if (err) {
console.log(err);
} else {
console.log(`${result} saved!`);
}
});
});