MongoDB是一種強大、靈活怀大、可擴展的數(shù)據(jù)存儲形式纱兑。他是面向文檔的數(shù)據(jù)庫,是NoSQL的一種化借。它擴展了關(guān)系型數(shù)據(jù)庫的眾多有用功能潜慎,如輔助索引、范圍查詢蓖康、和排序铐炫。還內(nèi)置了對MapReduce式聚合的支持,以及對地理空間索引的支持蒜焊。由于它放棄了關(guān)系型數(shù)據(jù)庫“行”的概念倒信,獲得了更加方便的擴展性。面向文檔的方式可以將文檔或數(shù)組內(nèi)嵌進來泳梆,所以用一條記錄就可以表示很復雜的層次關(guān)系堤结。
MongoDB沒有模式,文檔的鍵不會事先定義也不會固定不變鸭丛。
MongoDB從設(shè)計之初竞穷,就考慮了擴展的問題。他所采用的面向文檔的數(shù)據(jù)模型使之可以自動在多臺服務(wù)器之間分割數(shù)據(jù)鳞溉。它還可以平衡集群的數(shù)據(jù)和負載瘾带,自動重排文檔。如果需要更大的容量時熟菲,只需要向集群中增加新機器看政,數(shù)據(jù)庫就會自動幫我們處理剩下的事情朴恳。
文檔是MongoDB的核心概念。多個鍵及其相關(guān)聯(lián)的值有序的放在一起就是文檔允蚣。MongoDB不但飯區(qū)分類型于颖,還區(qū)分大小寫。
集合collection就是一組文檔嚷兔。MongoDB中的文檔有點類似關(guān)系型數(shù)據(jù)庫中的行森渐,集合有點類似于關(guān)系型數(shù)據(jù)庫中的表。但是與關(guān)系型數(shù)據(jù)庫不同的是冒晰,MongoDB的集合是沒有模式的同衣。但是在同一個集合中使用多種模式,不管對于開發(fā)者還是管理者壶运,都是一個噩夢耐齐。所以我們會使用多個集合。將同種類型的文檔放在同一個集合蒋情,數(shù)據(jù)會更加集中埠况,可以節(jié)省查詢時間,創(chuàng)建索引時也可以變得十分高效棵癣。多個集合可以使我們的查詢更加便捷辕翰,我們不需要從所有的數(shù)據(jù)中找我們需要的,只需要去相應(yīng)的集合中查詢就可以了浙巫。
常用指令
1.創(chuàng)建數(shù)據(jù)庫
MongoDB不需要專門的創(chuàng)建數(shù)據(jù)庫語句金蜀,直接使用use DataBaseName命令,如果數(shù)據(jù)庫存在的畴,則使用該數(shù)據(jù)庫渊抄。如果該數(shù)據(jù)庫不存在,則新建該數(shù)據(jù)庫丧裁。
> use newdb
switched to db newdb
在 MongoDB 中默認數(shù)據(jù)庫是:test
2.刪除數(shù)據(jù)庫
使用db.dropDatabase()命令可以刪除數(shù)據(jù)庫护桦。如果沒有選擇任何數(shù)據(jù)庫,那么它將刪除默認的’test‘數(shù)據(jù)庫
3.查詢數(shù)據(jù)庫列表
>show dbs
local 0.000025GB
test 0.00002GB
4.創(chuàng)建Collection
先通過use DataBaseName命令選中想要創(chuàng)建集合的數(shù)據(jù)庫煎娇,使用命令db.createCollection("collectionName")創(chuàng)建collection
>use newdb
switched to db newdb
>db.createCollection("mycollection")
{ "ok" : 1 }
>
4.刪除集合
MongoDB 的 db.collection.drop() 用于從數(shù)據(jù)庫中刪除集合
5.插入文檔
使用insert()命令插入到MongoDB集合中二庵。
db.CollectionName.insert(
{
"_id":"100",
"title":"MongoDB",
"description":"Description of MongoDB",
"url":"http://www.baidu.com"
}
)
如果不在文檔中指定_id,insert方法會自動為文檔分配id.
一次插入多個文檔,可以在insert()語句中插入多個文檔缓呛。文檔用逗號隔開催享,再使用中括號把所有文檔括起來。
db.CollectionName.insert([
{
_id: 101,
title: 'MongoDB Guide',
description: 'MongoDB is no sql database',
by: 'yiibai tutorials',
url: 'http://www.yiibai.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: 102,
title: 'NoSQL Database',
description: "NoSQL database doesn't have tables",
by: 'yiibai tutorials',
url: 'http://www.yiibai.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 210,
comments: [
{
user:'user1',
message: 'My first comment',
dateCreated: new Date(2017,11,10,2,35),
like: 0
}
]
},
{
_id: 104,
title: 'Python Quick Guide',
description: "Python Quick start ",
by: 'yiibai tutorials',
url: 'http://www.yiibai.com',
tags: ['Python', 'database', 'NoSQL'],
likes: 30,
comments: [
{
user:'user1',
message: 'My first comment',
dateCreated: new Date(2018,11,10,2,35),
like: 590
}
]
}
])
6.查詢文檔
使用db.COLLECTION_NAME.find(document)
查詢文檔哟绊。find()方法會找出collection中的所有文檔因妙。
帶參find()方法,第一個參數(shù)用來指定查詢條件,第二個參數(shù)用來表示要檢索的字段列表攀涵。字段列表對應(yīng)值設(shè)置為1即為顯示铣耘,設(shè)置為0即為隱藏字段。
> db.mycol.find({}, {'_id':1, 'title':1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "MongoDB Overview" }
>
第一個參數(shù)可以指定查詢過濾器以故,或類似關(guān)系型數(shù)據(jù)庫指定一些操作符或查詢運算符
>db.mycol.find({"likes": {$gt:10}, $or: [{"by": "yiibai tutorials"},
{"title": "MongoDB Overview"}]}).pretty() #and 和 or一起使用
{
"_id": 100,
"title": "MongoDB Overview",
"description": "MongoDB is no sql database",
"by": "yiibai tutorials",
"url": "http://www.yiibai.com",
"tags": ["mongodb", "database", "NoSQL"],
"likes": "100"
}
>
查詢限制數(shù)量
使用db.COLLECTION_NAME.find().limit(NUMBER)指令可以限制查詢NUMBER條
查詢跳過條目
使用skip()函數(shù)跳過一定量的些條目db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
7.更新文檔
update方法更新現(xiàn)有文檔中的值db.COLLECTION_NAME.update(SELECTION_CRITERIA, UPDATED_DATA)
>db.mycol.update({'title':'MongoDB Overview'},
{$set:{'title':'New Update MongoDB Overview'}},{multi:true})
save()方法傳遞新的文檔數(shù)據(jù)替換現(xiàn)有文檔
8.聚合
在關(guān)系型數(shù)據(jù)庫中使用count(*)和group by組合產(chǎn)生聚合功能蜗细,而在MongoDB中應(yīng)該使用aggregate()函數(shù)
假設(shè)我們的集合中有以下數(shù)據(jù)
db.article.insert([
{
_id: 100,
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'Maxsu',
url: 'http://www.yiibai.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: 101,
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'Maxsu',
url: 'http://www.yiibai.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: 102,
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Kuber',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},
{
_id: 103,
title: 'MySQL Overview',
description: 'MySQL is sql database',
by_user: 'Curry',
url: 'http://www.yiibai.com/mysql/',
tags: ['MySQL', 'database', 'SQL'],
likes: 350
}])
現(xiàn)在從上面的集合中,如果要顯示一個列表怒详,說明每個用戶寫入了多少個教程炉媒,那么可使用以下aggregate函數(shù)
> db.article.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{ "_id" : "Curry", "num_tutorial" : 1 }
{ "_id" : "Kuber", "num_tutorial" : 1 }
{ "_id" : "Maxsu", "num_tutorial" : 2 }
>
9.主從復制
主從復制是MongoDB最常用的復制的方式,可用于備份棘利、故障恢復橱野、讀擴展等朽缴。
首先需要建立一個主節(jié)點和一個或多個從節(jié)點善玫,每個從節(jié)點需要知道主節(jié)點的地址。運行mongod -master啟動主節(jié)點密强。運行mongod --slave --source master_address啟動從節(jié)點茅郎。
生產(chǎn)環(huán)境下可能會有多臺服務(wù)器,我們在同一臺服務(wù)器上替代實驗或渤。首先需要給主節(jié)點建立數(shù)據(jù)目錄系冗,并綁定端口號(10000):
$ mkdir -p ~/dbs/master
$ ./mongod --dbpath ~/dbs/master --port 10000 --master
接著設(shè)置從節(jié)點,需要選擇不同的目錄和端口薪鹦,并且使用--source為從節(jié)點指明主節(jié)點的地址:
$ mkdir -p ~/dbs/slave
$ ./mongod --dbpath ~/dbs/slave --port 10001 --slave --source localhost:10000
這種方式只能從節(jié)點從主節(jié)點復制掌敬,還沒有能夠從從節(jié)點復制的機制,因為從節(jié)點不保存自己的oplog池磁。
10.副本集
副本集是具有自動故障恢復的主從集群奔害。主從集群沒有固定的主節(jié)點,整個集群會推舉出一個主節(jié)點地熄,檔主節(jié)點無法工作時华临,變更到其他的節(jié)點。即端考,副本集總會有一個活躍節(jié)點(primary)和一個或多個備份節(jié)點(secondary)雅潭。
現(xiàn)在我們來將獨立的MongoDB實例轉(zhuǎn)換為副本集。
首先我們需要找到機器的主機名
$ cat /etc/hostname
morton
接著我們要關(guān)機現(xiàn)有的MongoDB服務(wù)器却特,啟動新的服務(wù)器
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
--replSet的作用是讓服務(wù)器知道扶供,這個rs0服務(wù)器還有其他的同伴還未啟動。
以同樣的方式啟動多臺裂明。
然后在shell中椿浓,連接其中一個服務(wù)器(使用morton:10001),初始化副本集:
$ ./mongo morton:10001/admin
11.MongoDB的關(guān)聯(lián)關(guān)系
MongoDB中的關(guān)系指的是各個文檔之間在邏輯上的相互關(guān)聯(lián)。關(guān)系可以使用嵌入式和引用方法兩種方式構(gòu)建轰绵。這種關(guān)系可以是1:1,1:N,N:N粉寞。
假設(shè)我們需要存儲用戶和用戶的地址。而一個用戶可以有多個地址左腔,這就是一個1:N的關(guān)系唧垦。
以下是用戶文檔結(jié)構(gòu):
{
"_id":10999110,
"name": "Maxsu",
"contact": "13888990021",
"dob": "1992-10-11"
}
以下是地址(address)文檔的結(jié)構(gòu):
{
"_id":12200,
"building": "Hainan Building NO.2100",
"pincode": 571100,
"city": "Haikou",
"province": "Hainan"
}
下面分別通過嵌入式和引用式兩種方式來構(gòu)建關(guān)系:
嵌入式
在嵌入式方法中,我們直接將地址文檔(address)嵌入到用戶(user)文檔中去液样。
{
"_id": 21000100,
"contact": "13800138000",
"dob": "1991-11-11",
"name": "Maxsu",
"address": [
{
"building": "Hainan Building NO.2100",
"pincode": 571100,
"city": "Haikou",
"province": "Hainan"
},
{
"building": "Sanya Building NO.2100",
"pincode": 572200,
"city": "Sanya",
"province": "Hainan"
},
]
}
這種方式將數(shù)據(jù)保存在同一個文檔中振亮,數(shù)據(jù)的檢索和維護比較容易。
> db.users.findOne({"name":"Maxsu"},{"address":1, "name":1})
但是如果嵌入式文檔不斷增大鞭莽,就會影響到讀寫的性能坊秸。
引用
這是設(shè)計規(guī)范化關(guān)系的方法。 在這種方法中澎怒,用戶和地址文件將分別維護褒搔,但用戶文檔將包含一個將引用地址文檔的id字段的字段。
我們可以將addresswen文檔存在其它的集合中喷面,將其引用添加到用戶文檔即可星瘾。我們使用使用DBRefs來引用文檔。它適用于文檔引用多個集合中的文檔的情況惧辈。
{
"_id": 21000100,
"contact": "13800138000",
"dob": "1991-11-11",
"name": "Maxsu",
"address": [
{
"$ref":"address_home",
"$id":ObjectId("12200"),
"$db":"myDB"
},
{
"$ref":"address_home",
"$id":ObjectId("12201"),
"$db":"myDB"
},
]
}
DBRefs中有三個字段 -
-
$ref
- 此字段指定引用文檔的集合 -
$id
- 此字段指定引用文檔的_id
字段 -
$db
- 這是一個可選字段琳状,并包含引用文檔所在的數(shù)據(jù)庫的名稱
接下來我們就可以通過引用查到用戶的地址。
>var user = db.users.findOne({"name":"Maxsu"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})
12.Map Reduce
Map-reduce是將大量數(shù)據(jù)合并為有用的聚合結(jié)果的數(shù)據(jù)處理范例盒齿。MapReduce通常用于處理大型數(shù)據(jù)集念逞。MongoDB使用MapReduce可以構(gòu)建出大型復雜聚合查詢。
以下是基本 mapReduce 命令的語法 -
>db.collection.mapReduce(
function() {emit(key,value);}, //map function
function(key,values) {return reduceFunction}, { //reduce function
out: collection,
query: document,
sort: document,
limit: number
}
)
map-reduce函數(shù)首先查詢集合边翁,然后將結(jié)果文檔映射到發(fā)出的鍵值對翎承,然后根據(jù)具有多個值的鍵進行減少。
在上面的語法 -
map是一個JavaScript函數(shù)倒彰,它將一個值與一個鍵映射并發(fā)出一個鍵值對审洞;
reduce是一個javascript功能,可以減少或分組具有相同鍵的所有文檔待讳;
out指定map-reduce查詢結(jié)果的位置芒澜;
query指定選擇文檔的可選選擇條件;
sort指定可選的排序條件创淡;
limit指定可選的最大文檔數(shù)痴晦;
接下來我們來使用MapReduce
考慮存儲用戶帖子的以下文檔結(jié)構(gòu)。 該文檔存儲用戶的user_name和帖子的狀態(tài)(status)琳彩。
{
"post_text": "abcd",
"user_name": "maxsu",
"status":"active"
}
現(xiàn)在我們需要選出所有status為active的帖子誊酌,并根據(jù)user_name進行分組
>db.posts.mapReduce(
function() { emit(this.user_id,1); },
function(key, values) {return Array.sum(values)}, {
query:{status:"active"},
out:"post_total"
}
)
返回結(jié)果
{
"result" : "post_total",
"timeMillis" : 9,
"counts" : {
"input" : 4,
"emit" : 4,
"reduce" : 2,
"output" : 2
},
"ok" : 1,
}
結(jié)果表明:共有4個文檔與查詢匹配部凑,mapper函數(shù)發(fā)出4哥鍵值對文檔,最終將具有相同鍵的reduce函數(shù)分組的映射文檔分解為2碧浊。在MapReduce函數(shù)后直接加find()函數(shù)就可以將我們想要的條目查詢出來涂邀。查詢結(jié)果如下:
{ "_id" : "tom", "value" : 2 }
{ "_id" : "maxsu", "value" : 2 }
13.文本搜索
從MongoDB 2.4開始,默認文本搜索功能是自動啟用狀態(tài)箱锐。
假設(shè)我們需要查詢一些博客比勉。我們先新建blogs集合。然后在blogs集合中插入一些文檔驹止。
db.blogs.insert({_id:1,title:"search",content:"MongoDB search"})
db.blogs.insert({_id:2,title:"Map Reduce",content:"Map-reduce"})
只有擁有Text index的collection才可以全文檢索浩聋,因此我們需要構(gòu)建Text index。一個collection只能有一個Text index臊恋,但是一個Text index可以有多個字段衣洁。
db.blogs.ensureIndex({title:"text",content:"text"})
接下來我們就可以通過索引去搜索。
簡單的全文搜索
db.blogs.find({$text:{$search:"MongoDB"}})
返回值
{_id:1,title:"search",content:"MongoDB search"}
查詢包含MongoDB不包含Map的記錄
db.blogs.find({$text:{$search:"MongoDB -Map"}})
返回值
{_id:1,title:"search",content:"MongoDB search"}
查詢含有MongoDB search的條目
db.blogs.find({$text:{$search:"\"MongoDB search\""}})
使用權(quán)重排序搜索結(jié)果
默認情況下抖仅,全文搜索是無順序的坊夫,但是我們可以使用$meta textScore來獲得每個文檔對這個搜索的匹配程度,并使用其進行排序
1
db.blogs.find( {$text:{$search:"MongoDB"}}, {score:{$meta:"textScore"}} ).sort({score:{$meta:"textScore"}})