MongoDB數(shù)據(jù)庫的使用
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
作者 | eliwang
來源 | urlify.cn/reMB3i
MongoDB是一個(gè)基于分布式 文件存儲的NoSQL數(shù)據(jù)庫,適合存儲JSON風(fēng)格文件的形式。
三元素:數(shù)據(jù)庫、集合和文檔。
文檔:對應(yīng)著關(guān)系數(shù)據(jù)庫中的行,就是一個(gè)對象,由鍵值對構(gòu)成,是json的擴(kuò)展Bson形式,示例
{'name':'guojing','gender':'男'}集合:類似于關(guān)系數(shù)據(jù)庫中的表,儲存多個(gè)文檔,結(jié)構(gòu)不固定,示例
{'name':'guojing','gender':'男'}
{'name':'huangrong','age':18}
{'book':'shuihuzhuan','heros':'108'}
一、環(huán)境安裝與運(yùn)行
安裝
sudo apt-get install mongodb
配置文件為 /etc/mongodb.conf,默認(rèn)端口號:27017
啟動服務(wù)器
sudo service mongodb start #相當(dāng)于執(zhí)行命令 sudo mongod --config /etc/mongod.conf關(guān)閉服務(wù)器
sudo service mongodb stop
重啟服務(wù)器
sudo service mongodb restart #修改了配置文件/etc/mongodb.conf后,需要重啟mongodb服務(wù)器讓配置生效
啟動客戶端
sudo mongo
二、數(shù)據(jù)庫操作
查看當(dāng)前數(shù)據(jù)庫
db
查看所有數(shù)據(jù)庫
show dbs
切換(或創(chuàng)建)數(shù)據(jù)庫
use 數(shù)據(jù)庫名
切換數(shù)據(jù)庫,如果數(shù)據(jù)庫不存在,當(dāng)插入數(shù)據(jù)或創(chuàng)建集合時(shí),會自動創(chuàng)建這個(gè)數(shù)據(jù)庫
刪除數(shù)據(jù)庫
db.dropDatabase()
刪除當(dāng)前指向的數(shù)據(jù)庫,如果不存在,則什么也不做
三、集合操作
創(chuàng)建
db.createCollection(name[,options])
#name集合名稱
#options可選,是一個(gè)用于指定集合配置的文檔,其中capped參數(shù)默認(rèn)不設(shè)置上限(false),若設(shè)置上限(true)則需要指定參數(shù)size,單位字節(jié)#不設(shè)置集合大小
db.createCollection("stu")
#設(shè)置集合大小
db.createCollection("sub", { capped : true, size : 10 } )查看當(dāng)前數(shù)據(jù)庫集合
show collections
刪除集合
db.集合名.drop()
四、數(shù)據(jù)操作
插入
db.集合名.insert(文檔) 或 db.集合名.insert([文檔...])
#如果不指定_id字段,則分配一個(gè)唯一的ObjectId;如果指定_id字段,且_id已經(jīng)存在時(shí),不做任何操作;如果一次性插入多條數(shù)據(jù),以數(shù)組的方式傳入文檔# 不指定_id
db.stu.insert({name:'gj',gender:1})
#指定_id
s1={_id:'20160101',name:'hr'}
s1.gender=0
db.stu.insert(s1)刪除--(注意justOne參數(shù))
db.集合名.remove(條件,{justone:<boolean>}) #參數(shù)justOne默認(rèn)false,刪除多條# 只刪除匹配到的一條數(shù)據(jù)
db.stu.remove({gender:0},{justOne:true})
#刪除所有
db.stu.remove({})修改--(注意$set以及multi參數(shù))
db.集合名.update({條件},$操作符,{multi: <boolean>}]) #參數(shù)multi只和$操作符一起使用,默認(rèn)false,只修改一條數(shù)據(jù),true表示修改多條數(shù)據(jù)# 不使用操作符$set,修改整條文檔
db.stu.update({name:'hr'},{name:'mnc'})
#使用操作符$set指定屬性修改
db.stu.update({name:'hr'},{$set:{name:'hys'}})
#multi參數(shù)和$set一起使用,修改多條文檔
db.stu.update({},{$set:{gender:0}},{multi:true})保存
db.集合名.save(document)
#在手動插入_id字段時(shí),如果_id已經(jīng)存在,做全文檔更新操作,其余均表示插入數(shù)據(jù)。db.stu.save({_id:'20160102','name':'yk',gender:1})
db.stu.save({_id:'20160102','name':'wyk'}) #對上述文檔做修改查詢
基本查詢
db.集合名.find({條件文檔}) #查詢所有
db.集合名.findOne({條件文檔}) #只查詢第一條
db.集合名.find({條件文檔}).pretty() #結(jié)果格式化輸出比較運(yùn)算符
等于:默認(rèn),沒有運(yùn)算符
小于:$lt
小于等于:$lte
大于:$gt
大于等于:$gte
不等于:$ne
#查詢年齡大于等于18的學(xué)生
db.stu.find({"age":{$gte:18}})邏輯運(yùn)算符
邏輯與:默認(rèn)
邏輯或:$or
# 查詢年齡大于或等于18,并且性別為1的學(xué)生
db.stu.find({"age":{$gte:18},"gender":1})
#查詢年齡大于18,或性別為0的學(xué)生
db.stu.find({$or:[{"age":{$gt:18}},{"gender":1}]})
#查詢年齡小于18或者大于20,性別為1的學(xué)生
db.stu.find({$or:[{"age":{$lt:18}},{"age":{$gt:20}}],"gender":1})范圍運(yùn)算符
在某個(gè)范圍$in,后面接數(shù)組
不在某個(gè)范圍$nin,后面接數(shù)組
#查詢年齡18、20以及22歲的學(xué)生
db.stu.find({"age":{$in:[18,20,22]}})
#查詢年齡不等于18或20的學(xué)生
db.stu.find({"age":{$nin:[18,20]}})正則表達(dá)式
使用/表達(dá)式/或者$regex
#查詢姓黃的學(xué)生
db.stu.find({"name":/^黃/})
db.stu.find({"name":{$regex:"^黃"}})自定義查詢
使用$where:function(){return 滿足條件的數(shù)據(jù)表達(dá)式}------運(yùn)算符使用js語法,比如邏輯與(&&),邏輯或(||)
#查詢年齡18-22的學(xué)生
db.stu.find({$where:function(){return this.age>18 && this.age<22}})
#查詢年齡小于18或者大于22的學(xué)生
db.stu.find({$where:function(){return this.age<18 || this.age>22}})投影
只顯示部分字段
db.集合名.find({條件},{字段名:1,...}) #1表示該字段顯示,0不顯示;_id列默認(rèn)顯示,不顯示需要明確設(shè)置為0#查詢姓名和年齡(顯示_id)
db.stu.find({},{name:1,gender:1})
#查詢姓名和年齡(不顯示_id)
db.stu.find({},{_id:0,name:1,gender:1})skip
跳過指定數(shù)量的文檔
db.集合名.find({條件}).skip(number) #number默認(rèn)為0#查詢從第3條開始的學(xué)生信息
db.stu.find().skip(2)limit
讀取指定數(shù)量的文檔
db.集合名.find({條件}).limit(number) #不寫number參數(shù),默認(rèn)讀取所有文檔#讀取3條學(xué)生信息
db.stu.find().limit(3)skip和limit合用
不區(qū)分先后順序
#查詢第5-9條學(xué)生信息
db.stu.find().skip(4).limit(5) #相當(dāng)于跳過4條數(shù)據(jù),選5條sort
對結(jié)果集進(jìn)行排序
db.集合名稱.find({條件}).sort({字段:1,...}) #1表示升序,-1表示降序#根據(jù)性別降序,再根據(jù)年齡升序
db.stu.find().sort({"gender":-1,"age":1})count
對結(jié)果集中文檔數(shù)目進(jìn)行統(tǒng)計(jì),返回整數(shù)
db.集合名.find({條件}).count()
或者
db.集合名.count({條件})#統(tǒng)計(jì)年齡大于20的男生人數(shù)
db.stu.count({"age":{$gt:20},"gender":1})distinct
對數(shù)據(jù)去重,返回的是一個(gè)列表
db.集合名.distinct("字段名",{條件})
五、聚合(aggregate)
聚合主要用于計(jì)算數(shù)據(jù),類似sql中的sum()、avg()
db.集合名.aggregate([{管道:{表達(dá)式}}...])管道
$group:將集合中的文檔分組,可用于統(tǒng)計(jì)結(jié)果
$match:過濾數(shù)據(jù),只輸出符合條件的文檔
$project:修改輸入文檔的結(jié)構(gòu),如重命名、增加、刪除字段、創(chuàng)建計(jì)算結(jié)果
$sort:將輸入文檔排序后輸出
$limit:限制聚合管道返回的文檔數(shù)
$skip:跳過指定數(shù)量的文檔,并返回余下的文檔
$unwind:將數(shù)組類型的字段進(jìn)行拆分
文檔處理完畢后,通過管道進(jìn)行下一次處理
常用管道:
表達(dá)式
$sum:計(jì)算總和,$sum:'$字段'表示求和,注意$sum:1表示計(jì)數(shù),
$avg:計(jì)算平均值
$min:獲取最小值
$max:獲取最大值
$push:在結(jié)果文檔中插入值到一個(gè)數(shù)組中(以列表的方式顯示字段值)
$first:根據(jù)資源文檔的排序獲取第一個(gè)文檔數(shù)據(jù)
$last:根據(jù)資源文檔的排序獲取最后一個(gè)文檔數(shù)據(jù)
處理輸入文檔并輸出
語法:表達(dá)式:‘$字段名’
常用表達(dá)式:
$group
文檔分組,用于統(tǒng)計(jì)結(jié)果
_id表示分組的依據(jù),使用某個(gè)字段的格式為'$字段'
# 統(tǒng)計(jì)男、女生人數(shù)
db.stu.aggregate([{$group:{"_id":'gender',"couter":{$sum:1}}}])
#結(jié)果文檔中顯示_id和counter的值_id按照null分組,會將集合中所有文檔分為一組
# 求學(xué)生總?cè)藬?shù)和平均年齡
db.stu.aggregate([{$group:{_id:null,counter:{$sum:1},average_age:{$avg:"$age"}}}])使用$$ROOT可以將文檔內(nèi)容加入到結(jié)果集的數(shù)組中
#統(tǒng)計(jì)男、女生信息
db.stu.aggregate([{$group:{_id:"$gender",objects:{$push:"$$ROOT"}}}])$match
過濾數(shù)據(jù),輸出符合條件文檔
#查詢年齡大于20的學(xué)生
db.stu.aggregate([{$match:{age:{$gt:20}}}])
#查詢年齡大于20的男、女生人數(shù)
db.stu.aggregate([{$match:{age:{$gt:20}}},{$group:{_id:"$gender",counter:{$sum:1}}}])$project
修改輸出文檔的結(jié)構(gòu)
#查找學(xué)生姓名、年齡
db.stu.aggregate([{$project:{"_id":0,"name":1,"age":1}}])
#查詢男生、女生人數(shù),但僅輸出人數(shù)
db.stu.aggregate([{$group:{_id:'$gender',counter:{$sum:1}}},{$project:{_id:0,counter:1}}])$sort
將輸入文檔排序后輸出
#查詢學(xué)生信息,按年齡升序
db.stu.aggregate([{$sort:{age:1}}])
#查詢男生、女生人數(shù),按人數(shù)降序
db.stu.aggregate([{$group:{_id:'$gender',counter:{$sum:1}},{$sort:{counter:-1}}])$limit
限制聚合管道返回的文檔數(shù)
#查詢2條學(xué)生信息
db.stu.aggregate([{$limit:2}])$skip
跳過指定數(shù)量的文檔,并返回余下的文檔,$skip和$limi合用時(shí),注意先寫skip,再寫limit
#查詢從第3條開始的學(xué)生信息
db.stu.aggregate([{$skip:2}])
#統(tǒng)計(jì)男生、女生人數(shù),按人數(shù)升序,取第二條數(shù)據(jù)
db.stu.aggregate([{$group:{_id:"$gender",counter:{$sum:1}}},{$sort:{"counter":1}},{$skip:1},{$limit:1}])$unwind
將文檔中的某一個(gè)數(shù)組類型字段拆分成多條,每條包含數(shù)組中的一個(gè)值
db.集合名稱.aggregate([{$unwind:'$字段名稱'}])
六、索引
提升查詢速度
創(chuàng)建大量數(shù)據(jù)
for(var i=0;i<1000000;i++){db.stu.insert({name:'test'+i,num:i})}性能分析工具:explain("executionStats")
查詢語句.explain("executionStats")
'millis'后面顯示的是查詢時(shí)間,單位ms
建立索引
db.集合.ensureIndex({屬性:1或-1}) #1表示升序,-1表示降序,建立后的索引名稱為"屬性_1"或者"屬性_-1"例如:db.stu.ensureIndex({name:1}),建立后的索引名稱為"name_1"
建立唯一索引
db.集合.ensureIndex({屬性:1},{"unique":true})建立聯(lián)合索引
db.集合名.ensureIndex({屬性1:1,屬性2:1...})查看索引
db.集合名.getIndexes()
刪除索引
db.集合名.dropIndex("索引名稱")
七、數(shù)據(jù)庫安全
為了更安全的訪問mongodb,需要訪問者提供用戶名和密碼,于是需要在mongodb中創(chuàng)建用戶。mongodb數(shù)據(jù)庫采用了角色-用戶-數(shù)據(jù)庫的安全管理方式。
常用系統(tǒng)角色如下:
root:只在admin數(shù)據(jù)庫中可用,超級賬號,超級權(quán)限
Read:允許用戶讀取指定數(shù)據(jù)庫
readWrite:允許用戶讀寫指定數(shù)據(jù)庫
創(chuàng)建超級管理用戶:
use admin #首先切換到admin數(shù)據(jù)庫
db.createUser({
user:'用戶名',
pwd:'密碼',
roles:[{role:'root',db:'admin'}]
})啟用安全驗(yàn)證
修改配置文件( /etc/mongodb.conf)
#noauth = true
auth = true #開啟安全驗(yàn)證重啟服務(wù)
sudo service mongodb restart
終端連接
# sudo mongo -u '用戶名' -p '密碼' --authenticationDatabase '數(shù)據(jù)庫名'
sudo mongo -u 'admin' -p '密碼' --authenticationDatabase 'admin'普通用戶管理
首先使用超級管理員登陸,然后再進(jìn)行用戶管理操作
創(chuàng)建普通用戶
db.createUser({
user:'用戶名',
pwd:'密碼',
roles:[{role:'readWrite',db:'數(shù)據(jù)庫名'}...] #數(shù)組里可以有多個(gè)角色文檔,比如用戶在不同的數(shù)據(jù)庫里都有讀寫權(quán)限
})查看當(dāng)前數(shù)據(jù)庫的用戶
show users
修改用戶:可以修改pwd、roles屬性
db.updateUser('用戶名',{pwd:'新密碼',roles:[{'新角色'}...]})
刪除用戶
use admin #切換到admin數(shù)據(jù)庫
db.system.users.remove(條件)終端連接
sudo mongo -u '用戶名' -p '密碼' --authenticationDatabase '數(shù)據(jù)庫名'
八、復(fù)制
復(fù)制提供了數(shù)據(jù)的冗余備份,并在多個(gè)服務(wù)器上存儲數(shù)據(jù)的副本,允許從硬件故障和服務(wù)中斷中恢復(fù)數(shù)據(jù),能夠?qū)崿F(xiàn)無宕機(jī)維護(hù)(自動故障轉(zhuǎn)移與自動恢復(fù))。
復(fù)制至少需要2個(gè)節(jié)點(diǎn),其中1個(gè)為主節(jié)點(diǎn),其它均為從節(jié)點(diǎn)。任何節(jié)點(diǎn)均可以成為主節(jié)點(diǎn)。
主節(jié)點(diǎn)負(fù)責(zé)所有寫入操作,從節(jié)點(diǎn)定期輪詢主節(jié)點(diǎn)獲取這些操作并執(zhí)行這些操作,從而保證從節(jié)點(diǎn)的數(shù)據(jù)與主節(jié)點(diǎn)一致。
設(shè)置復(fù)制節(jié)點(diǎn)
創(chuàng)建數(shù)據(jù)庫文件存放目錄(自定義)
mkdir ~/Desktop/t1
mkdir ~/Desktop/t2使用如下格式啟動mongod,如果在同一臺主機(jī)上,注意port不能相同,replSet的名稱必須是一致的(名稱可以自定義)
sudo mongod --bind_ip 192.168.196.128 --port 27017 --dbpath ~/Desktop/t1 --replSet rs0
sudo mongod --bind_ip 192.168.196.128 --port 27018 --dbpath ~/Desktop/t2 --replSet rs0連接主服務(wù)器(自定義一個(gè))
sudo mongo --host 192.168.196.128 --port 27017
初始化
rs.initiate()
哪個(gè)服務(wù)器執(zhí)行初始化,哪個(gè)服務(wù)器就作為主節(jié)點(diǎn),rs是mongo服務(wù)器中專門用于復(fù)本集操作的內(nèi)置對象
查看當(dāng)前狀態(tài)
rs.status()
添加副本集
rs.add("192.168.127.128:8899")
連接從服務(wù)器
sudo mongo --host 192.168.196.128 --port 27018
從服務(wù)器設(shè)置
rs.slaveOk()
主服務(wù)器插入數(shù)據(jù),從服務(wù)器就可以讀取數(shù)據(jù)了
刪除從節(jié)點(diǎn)
rs.remove('192.168.196.128:27018') #需要在主服務(wù)器操作
關(guān)閉主服務(wù)器后再重新啟動,會發(fā)現(xiàn)原來的從服務(wù)器變?yōu)榱酥鞣?wù)器,新啟動的服務(wù)器(原來的主服務(wù)器)變?yōu)榱藦姆?wù)器,但是注意重新設(shè)置rs.slaveOk()
九、備份與恢復(fù)
備份
語法
sudo mongodump -h 服務(wù)器地址 -d 需要備份的數(shù)據(jù)庫 -o 備份數(shù)據(jù)存放目錄mkdir ~/Desktop/test1_bak #創(chuàng)建存放備份數(shù)據(jù)的目錄
sudo mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1_bak恢復(fù)
語法
sudo mongorestore -h 服務(wù)器地址 -d 恢復(fù)后數(shù)據(jù)庫名 --dir 備份數(shù)據(jù)所在位置sudo mongorestore -h 192.168.196.128:27017 -d test2 --dir ~/Desktop/test1_bak/test1
十、python交互
安裝pymongo包
sudo pip3 install pymongo
引入包
import pymongo建立連接并創(chuàng)建客戶端
有安全認(rèn)證:client=MongoClient("mongodb://用戶名:密碼@host:27017/數(shù)據(jù)庫名稱")
無安全認(rèn)證:client=MongoClient("mongodb://localhost: 27017")獲得數(shù)據(jù)庫(以test數(shù)據(jù)庫為例)
db = client.數(shù)據(jù)庫名
例如:db = client.test獲得集合stu
stu = db.stu
數(shù)據(jù)操作
查詢
find_one 查找單個(gè)文檔
stu1 = stu.find_one({條件}) #返回一條文檔,字典類型find 查找多個(gè)文檔
cursor = stu.find({條件}) #返回迭代器對象cursor
#方式1:用for循環(huán)迭代取值
for s in cursor:
print(s) #字典類型
#方式2:用next取值
s1 = next(cursor)
s2 = next(cursor)
...插入
insert_one 插入一條文檔
stu.insert_one(文檔)insert_many 插入多條文檔
stu.insert_many([文檔1,文檔2...])更新
update 更新匹配到的第一條整條文檔
stu.update({條件},文檔) #注意條件中的數(shù)字一定要寫成字符串類型update_one 與$set一起使用,指定屬性修改匹配到的第一條文檔
stu.update_one({條件},{$set:{文檔}})update_many 與$set一起使用,指定屬性修改多條文檔
stu.update_many({條件},{$set:{文檔}})刪除
delete_one 刪除單條文檔
stu.delete_one({條件})delete_many 刪除多條文檔stu.delete_many({條件})
粉絲福利:Java從入門到入土學(xué)習(xí)路線圖
??????

??長按上方微信二維碼 2 秒
感謝點(diǎn)贊支持下哈 
