一、MongoDB簡介
-
概述
MongoDB是一個基于分布式文件存儲的數據庫,由C++語言編寫。旨在為WEB應用提供可擴展的高性能數據存儲解決方案。MongoDB介于關系型數據和非關系型數據庫之間,是非關系數據庫當中功能最豐富,最像關系數據庫的。他支持的數據結構非常松散,類似json格式,因此可以存儲比較復雜的數據類型。
MongoDB最大的特點是他支持的查詢語言非常強大,其語法有點類似于面向對象的查詢語言,幾乎可以實現類似關系數據庫表單查詢的絕大部分功能,而且還支持對數據建立索引。
-
MySQL
關系型數據庫。 查詢語句是使用傳統的sql語句,擁有較為成熟的體系,成熟度很高。 關系型數據庫遵循ACID規則 開源數據庫的份額在不斷增加,mysql的份額頁在持續增長。 缺點:在海量數據處理的時候效率會顯著變慢。數據庫事務必須具備ACID特性,ACID是Atomic原子性,Consistency一致性,Isolation隔離性,Durability持久性。
數據的持久存儲,尤其是海量數據的持久存儲,還是需要一種關系數據庫。 -
MongoDB
非關系型數據庫(nosql ),屬于文檔型數據庫。存儲方式:虛擬內存+持久化。
查詢語句:是獨特的MongoDB的查詢方式。
適合場景:事件的記錄,內容管理或者博客平臺等等。
數據處理:數據是存儲在硬盤上的,只不過需要經常讀取的數據會被加載到內存中,將數據存儲在物理內存中,從而達到高速讀寫。
成熟度與廣泛度:新興數據庫,成熟度較低,Nosql數據庫中最為接近關系型數據庫,比較完善的DB之一,適用人群不斷在增長。
優勢: 快速!在適量級的內存的MongoDB的性能是非常迅速的,它將熱數據存儲在物理內存中,使得熱數據的讀寫變得十分快, 高擴展, json的存儲格式!文檔的數據庫: 即可以存放xml、json、bson類型系那個的數據。這些數據具備自述性(self-describing),呈現分層的樹狀數據結構。數據結構由鍵值(key=>value)對組成。
-
關系型數據庫和非關系型數據庫的區別
關系型數據庫通過外鍵關聯來建立表與表之間的關系;
非關系型數據庫通常指數據以對象的形式存儲在數據庫中,而對象之間的關系通過每個對象自身的屬性來決定;學生: 張三 性別: 男 科目: 語文 成績: 80 關系型數據庫: // 學生表 create table student(id int primary key, name char(50), sex char(10)) // 成績表,stuid存儲的是學生表中對應的主鍵,用于表的關聯 create table score(id int primary key, name char(20),grade int,stuid int, foreign key(stuid) references student(id)) 非關系型數據庫: { "name":"張三", "sex":"男", "score":{ "name":"語文", "grade": 80 } }
關系型數據庫SQLite、Oracle、mysql
非關系型數據庫 MongoDb、redis MySQL和MongoDB的區別
數據庫: 容器,不管是mysql還是mongodb,一個單一的服務器都可以管理多個數據庫;
集合:是一組mongodb的文件,等價于mysql中的table,集合中文檔可以有不同的字段,也可以有不同的數據類型;
二、MongoDB安裝和卸載
-
卸載
sudo apt-get autoremove mongodb sudo apt-get autoclean mongodb // 清除殘留數據 dpkg -l |grep ^rc|awk '{print $2}' |tr ["\n"] [" "]|sudo xargs dpkg -P
-
安裝
第1步 – 導入公鑰** Ubuntu軟件包管理器apt(高級軟件包工具)需要軟件分銷商的GPG密鑰來確保軟件包的一致性和真實性。 執行此下面的命令將MongoDB密鑰導入到您的服務器: sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5 第2步 – 創建源列表文件MongoDB 檢查URL http://repo.mongodb.org/apt/ubuntu/dists/。 如果您在該網頁上看到一個目錄“bionic”,則將下述命令中的單詞“xenial”替換為“bionic”一詞, 【原因:MongoDB尚未發布Bionic Beaver軟件包,但Xenial軟件包在Ubuntu 18.04 LTS上運行良好】 執行以下命令在/etc/apt/sources.list.d/中創建一個MongoDB列表文件: echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.6 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.6.list 第3步 – 更新存儲庫 使用apt命令更新存儲庫: sudo apt-get update 說明:執行完會提示一些失敗,不用在意 第4步 – 安裝MongoDB 執行以下命令來安裝MongoDB: sudo apt-get install -y mongodb 第5步:啟動MongoDB 執行以下命令啟動MongoDB并將其添加為在啟動時啟動的服務 sudo systemctl start mongodb 如果執行完這一步終端沒有任何輸出,則說明是正確的 如果啟動的時候提示:Failed to start mongod.service: Unit mongodb.service not found. 解決辦法如下: 1創建配置文件: cd /etc/systemd/system/ sudo vi mongodb.service 2.在里面追加文本: [Unit] Description=High-performance, schema-free document-oriented database After=network.target [Service] User=mongodb ExecStart=/usr/bin/mongod --quiet --config /etc/mongodb.conf [Install] WantedBy=multi-user.target 3.退出 :wq 4.啟動服務 sudo systemctl start mongodb sudo systemctl status mongodb 5.設置開機自啟動 sudo systemctl enable mongodb 第6步:登錄MongoDB mongo 如果出現錯誤全局初始化失敗:BadValue無效或無用戶區域設置。 請確保LANG和/或LC_ *環境變量設置正確,請嘗試命令: export LC_ALL=C
三、MongoDB之數據庫操作
-
創建數據庫
# mongodb use DATABASE_NAME 注意:如果指定的數據庫DATABASE_NAME不存在,則該命令將創建一個新的數據庫,否則返回現有的數據庫 # mysql中 創建數據庫:create database basename; 切換數據庫:use basename;
admin:從權限的角度來說,是root的數據庫
? local:本地數據
? config:配置,用于保存MongoDB的配置信息 -
檢查當前選擇的數據
db
默認的數據庫test
-
顯示數據庫列表
show dbs
-
刪除數據庫
// 默認進入數據庫是test db.dropDatabase()
注意:默認刪除當前正在工作的數據庫
四、MongoDB之集合操作
類似于MySQL中的表。
集合存在于數據庫中,集合沒有固定的結構,意味著可以對集合插入不同格式和不同類型的數據,但是盡量插入集合的時候保證數據的關聯性。
-
創建集合
集合名的規范: a.不能空字符串 b.集合名不能含有\0【空字符】,表示集合名的結尾 c.集合名不能以"system."開頭,為系統集合保留的關鍵字 d.不能含有保留字符,千萬不能含有$ 語法: // name的類型為String,是要創建的集合的名稱 // options的類型是Document,是一個文檔,指定相應的大小和索引,是可選參數 // 在插入文檔時,MongoDB首先檢查上限集合capped字段的大小,然后檢查max字段 db.createCollection(name, options) 例如: // 沒有options選項的集合創建 db.createCollection("myCollection") // 有options選項的集合的創建 db.createCollection("mycol",{capped:true,autoIndexId:true,size:1024,max:10000})
選項列表 -
顯示當前數據庫中的集合
show collections
-
刪除集合
語法: // 如果選定的集合成功刪除,drop()方法將返回true,否則返回false db.COLLECTION_NAME.drop() 例如: db.mycollection.drop()
五、MongoDB之文檔操作
-
文檔概念
文檔:相當表中的一條記錄【實體】
是一組鍵值對,文檔不需要設置相同的字段,并且相同的字段不需要相同的數據類型注意: a.文檔中的鍵值對是有序的 b.文檔中值除了字符串之外,還可以是其他數據類型【嵌套一個文檔】 c.嚴格區分大小寫和數據類型的,mycol myCol d.文檔中不能有重復的鍵 e.文檔中的鍵基本都是用字符串表示的
文檔中鍵的命名: a.鍵不能包含\0 b.$和.有特殊含義 c.以下劃線開頭的鍵是保留的,盡量不要使用下劃線開頭
-
插入文檔
語法: // 在插入的文檔中,如果不指定_id參數,那么 MongoDB 會為此文檔分配一個唯一的ObjectId // _id為集合中的每個文檔唯一的12個字節的十六進制數。 db.COLLECTION_NAME.insert(document) 例如: // 插入一個 db.mycol.insert({id:101, name:'lisi', age:20}) db.mycol.insert({ item: "canvas", num: 100, tags: ["cotton"], size: { h: 20, w: 30, } }) // 插入多個(注意方括號) db.mycol.insert( [{id:102, name:'wagnwu', age:18}, {id:103, name:'zhaoliu', age:21}, {id:104, name:'tianqi', age:19}] ) // 查看已插入的文檔 db.mycol.find() { "_id" : ObjectId("5b8b59cb5bd1df1fc73dcdc6"), "id" : 101, "name" : "lisi", "age" : 20 } // 查看已插入的文檔 db.mycol.find().pretty() { "_id" : ObjectId("5b8b59cb5bd1df1fc73dcdc6"), "id" : 101, "name" : "lisi", "age" : 20 }
-
查詢文檔
語法: // 基本操作 db.COLLECTION_NAME.find(document) // 以格式化的方式返回查詢結果 db.COLLECTION_NAME.find(document).pretty() 注意: find() 將以非結構化的方式返回查詢結果 例如: // 顯示所有文檔 db.mycol.find() // 默認將所有文檔顯示,為了限制列表,需要顯示的字段設置為1,不顯示的設置為0 db.mycol.find( {'name':'liming'}, {'name':1, 'age': 1} ) db.mycol.find( {'name':'liming'}, {'age':0} ) // 限制字段顯示 db.check.find({},{'_id':1,'title':1})
-
查詢文檔(條件查詢)
- 等于{ <key>:<value> } db.mycol.find({'name':'yhy'} ).pretty() - 小于 { <key>: {$lt:<value>} } db.mycol.find( {'age': {$lt:18}} ).pretty() - 小于等于 { <key>: {$lte:<value>} } db.mycol.find( {'age': {$lte:18}} ).pretty() - 大于 { <key>: {$gt:<value>} } db.mycol.find( {'age': {$gt:18}} ).pretty() - 大于等于 { <key>: {$gte:<value>} } db.mycol.find( {'age': {$gte:18}} ).pretty() - 不等于 { <key>: {$ne:<value>} } db.mycol.find( {'age': {$ne:18}} ).pretty() - 并列關系(and) 在find()方法中,如果通過使用 ',' 將它們分開傳遞多個鍵,則 MongoDB 將其視為AND條件 db.mycol.find( { $and: [ {key1: value1}, {key2: value2} ] } ) - 或者關系(or) db.mycol.find( { $or: [ {key1: value1}, {key2: value2} ] } )
-
更新文檔
update()更新現有文檔中的值,語法: db.COLLECTION_NAME.update(SELECTION_CRITERIA, UPDATED_DATA) 例如: // update默認只更新一個文檔,如果要更新多個文檔,則添加參數{multi:true}) db.check.update( {'title': 'MongoDB Guide'}, {$set: {'title': 'mongo'}} ) db.check.update( {'title': 'MongoDB Guide'}, {$set: {'title': 'mongo'}, $set: {'say': 'hello'}} ) db.check.update( {'title': 'MongoDB Guide'}, {$set: {'title': 'mongo'}}, {multi: true} ) save()用傳遞的文檔數據替換現有文檔,語法: db.COLLECTION_NAME.save({_id:ObjectId(),NEW_DATA}) 例如: db.check.save( {'_id':102, 'title':'hello', 'by':'lalala'} )
-
刪除文檔
語法: db.COLLECTION_NAME.remove(DELLETION_CRITTERIA) 例如: db.check.remove( {'_id':100} )
六、MongoDB之查詢
-
投影
查詢過程中,只顯示指定的字段語法: db.COLLECTION_NAME.find({},{KEY:1}) 例如: db.mycol.find( {}, {'title':1, _id:0} )
在執行find()方法時,始終都會顯示_id字段,如果不想要此字段,則需要將其設置為0
-
限制篩選記錄
limit()限制MongoDB要返回的記錄數,根據指定的參數返回記錄數 語法: db.COLLECTION_NAME.find().limit(NUMBER) 例如: // 在查詢文檔時僅顯示兩個文檔 db.mycol.find({},{"title":1,_id:0}).limit(2) skip() 方法跳過指定數量的數據 語法: // 注意:skip()方法中的默認值為0。 db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER) 例如: db.mycol.find({},{"title":1,_id:0}).limit(1).skip(2)
-
對查詢記錄排序
語法: // 使用指定順序進行排序,1表示升序,-1表示降序 db.COLLECTION_NAME.find().sort({KEY:1}) 例如: db.mycol.find({},{"title":1,_id:0}).sort({"title":-1})
-
管道的概念
MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢后將結果傳遞給下一個管道處理。管道操作是可以重復的。$project:修改輸入文檔的結構。可以用來重命名、增加或刪除域,也可以用于創建計算結果以及嵌套文檔 db.article.aggregate( [ {$project:{by_user:1, title:1}} ] ) $limit:用來限制MongoDB聚合管道返回的文檔數 db.article.aggregate( [ {$project:{by_user:1, title:1}}, {$limit: 2} ] ) $skip:在聚合管道中跳過指定數量的文檔,并返回余下的文檔 db.article.aggregate( [ {$project:{by_user:1, title:1}}, {$skip: 1} ] ) db.article.aggregate( [ {$project:{by_user:1, title:1}}, {$limit:2},{$skip: 1} ] ) $group:將集合中的文檔分組,可用于統計結果 db.article.aggregate( [ {$group: {_id:'$by_user', num:{$sum:'$likes'}}} ] ) $sort:將輸入文檔排序后輸出 db.article.aggregate( [ {$group: {_id:'$by_user', num:{$sum:'$likes'}}},{$sort: {'num':-1}} ] )
-
分組與聚合函數查詢
aggregate()語法: db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION) - $sum 從集合中的所有文檔中求出定義的值 // 計算每個作者所寫的文章點贊數 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) // 計算每個作者所寫文檔數量 // select by_user, count(*) from article group by by_user db.article.aggregate([ { $group: {_id:'$by_user', num:{$sum:1}} } ]) - $avg 計算集合中所有文檔的所有給定值的平均值 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) - $max 從集合中的所有文檔獲取相應值的最大值 // _id:'$by_user',對應按照by_user分組 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) // _id對應一個常量,即所有數據的操作 db.article.aggregate([ { $group:{_id:'max', num_likes:{$max:'$likes'}} } ]) - $min 從集合中的所有文檔獲取相應值的最小值 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) - 例如: db.article.aggregate([{$group:{'_id':'$by_user','num_tutorial':{$sum:1}}}])
七、MongoDB之關聯關系
MongoDB中的關系表示各個文檔在邏輯上的相互關聯。關系可以通過嵌入式和引用方法建模。 這種關系可以是1:1,1:N,N:1或N:N。
假設有一種情況:要存儲用戶的地址。一個用戶可以擁有多個地址,這就是1:N關系。
// 用戶user文檔
{
"_id":10999110,
"name": "Maxsu",
"contact": "13800138000",
"dob": "1992-10-11"
}
// 地址文檔
{
"_id":12200,
"building": "Hainan Building NO.2100",
"pincode": 571100,
"city": "Haikou",
"province": "Hainan"
}
嵌入式關系建模
在嵌入式方法中,我們將地址(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"
},
]
}
該方法將所有相關數據保存在單個文檔中,這使得檢索和維護更容易。
可以使用單個查詢來在整個文檔檢索:
db.users.find( {"name":"Maxsu"},{"address":1, "name":1} )
在上述查詢中,db和users分別是數據庫和集合。缺點是如果嵌入式文檔的大小如果不斷增長,可能會影響讀/寫性能。
建模參考關系
這是設計規范化關系的方法。
在這種方法中,用戶和地址文件將分別維護,但用戶文檔將包含一個將引用地址文檔的id字段的字段。
{
"_id":ObjectId("52ffc33321332111sdfaf"),
"contact": "13800138000",
"dob": "1991-11-11",
"name": "Maxsu",
"address_ids": [
ObjectId("123123"),
ObjectId("123412")
]
}
用戶文檔包含對應地址的ObjectId的數組字段address_ids。
使用這些ObjectIds,我們可以從那里查詢地址文件并獲取地址詳細信息。
使用這種方法,需要兩個查詢:首先從用戶文檔獲取address_ids字段,然后從地址集中獲取這些地址。
var result = db.users.find({"name":"Maxsu"},{"address_ids":1})
var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})
八、MongoDB與Python的交互
- 安裝
pip3 install pymongo
- 使用
import pymongo
from pymongo import MongoClient
from bson.objectid import ObjectId
#1.建立連接
#創建MongoClient的對象
#方式一
#特點:可以連接默認的主機和端口號
#client = MongoClient()
#方式二
#明確指明主機和端口號
#client = MongoClient('localhost',27017)
#client = MongoClient(host='localhost',port=27017)
#方式三
#使用MongoDB URI的
client = MongoClient('mongodb://localhost:27017')
#2.獲取數據庫
#MongoDB的一個實例可以支持多個獨立的數據庫
#可以通過MongoClient的對象的屬性來訪問數據庫
#方式一
db = client.test
print(db)
#方式二
#db = client['test']
#3.獲取集合
#集合是存儲在MongoDb中的一組文檔,可以類似于MySQl中的表
#方式一
collection = db.stuents
#方式二
#collection = db['students']
"""
注意:
MongoDB中關于數據庫和集合的創建都是懶創建
以上的操作在MongoDB的服務端沒有做任何操作
當第一個文檔被插入集合的時候才會創建數據庫和集合
"""
#4.文檔
#在pymongo中使用字典來表示文檔
student1 = {
'id':'20180101',
'name':'jack',
'age':20,
'gender':'male'
}
#5.插入文檔
#5.1insert()
#插入單條數據
#注意:MongoDb會自動生成一個ObjectId,insert函數的返回值為objectid
result = collection.insert(student1)
print(result)
#插入多條數據
student2 = {
'id':'20180530',
'name':'tom',
'age':30,
'gender':'male'
}
student3 = {
'id':'20180101',
'name':'bob',
'age':18,
'gender':'male'
}
#result = collection.insert([student2,student3])
#6.查詢文檔
#6.1
#find_one()
result = collection.find_one({'name':'jack'})
print(type(result)) #<class 'dict'>
print(result)
#6.2find()
#需求:查詢年齡為20的數據
results = collection.find({'age':20})
print(results)
#Cursor相當于是一個生成器,只能通過遍歷的方式獲取其中的數據
for r in results:
print(r)
#6.3其他用法
#a.count()
#統計所有數據的條數
count1 = collection.find().count()
#統計制定條件的數據條數
count1 = collection.find({'age':20}).count()
#7.更新文檔
#7.1update()
conditon = {'name':'jack'}
student = collection.find_one(conditon);
student['age'] = 30
result = collection.update(conditon,student)
#7.2update_one()
conditon = {'name':'jack'}
student = collection.find_one(conditon);
student['age'] = 30
result = collection.update_one(conditon,{'$set':student})
print(result.matched_count,result.modified_count)
#7.3update_many()
#查詢年齡大于20的數據,然后講年齡增加1
conditon = {'age':{'$gt':20}}
result = collection.update_one(conditon,{'$inc':{'age':1}})
print(result.matched_count,result.modified_count)
#8.刪除文檔
#8.1remove()
#將符合條件的所有的數據全部刪除
result = collection.remove({'name':'rose'})
#8.2delete_one()
result = collection.delete_one({'name':'rose'})
#8.3delete_many()
result = collection.delete_many({'name':'rose'})
備注: 默認MongoDB是綁定127.0.0.1,連接遠程是連接不了的。
編輯MongoDB配置文件: sudo vi /etc/mongodb.conf
找到bind_ip = 127.0.0.1
改為bind_ip = 0.0.0.0