簡介
NoSQL
NoSQL(非關係數據庫)對比MySql等傳統關係型數據庫的優點是更適合於大規模數據和多種數據的應用場景,尤其是大數據相關問題。NoSQL的應用場景是:
- 對數據庫併發讀取的需求
- 對海量數據高效率存儲和訪問的需求
- 對數據庫高擴展性和高可用性的需求
傳統數據庫是通過表、行、列來組織和存儲數據的,而NoSQL是用JSON來存儲數據。
MongoDb 介紹
MongoDB 是一個介於關係數據庫和非關係數據庫之間的產品,採用類似json的bson格式來存儲數據,因此可以存儲比較複雜的類型,這點也是我學習MondgoDB的最大原因,之前編寫iot後臺處理程序來存儲網關上傳的傳感器數據時使用的是序列化的json作爲字符串來存儲到mysql中的,因爲傳感器數據各種各樣,無法使用固定的結構,如果使用MongoDB就不會出現這種非規範化的操作了。
MongoDB支持類似面對對象的查詢語言,JSON
與js契合度高,而類似JSON
的BSON
類似,所以決定使用nodejs搭配MongoDB來實現第二代iot管理平臺的原型,具體另開文章來敘述。
安裝
略過,查看官網
環境變量配置
默認安裝後,如果要在cmd或者wsl中啓動,需要配置MongoDB的環境變量。win10的操作如下:
開始菜單欄搜索“環境變量”,打開後選擇高級
標籤頁,點擊環境變量
,選擇path,將MongoDB中bin文件夾路徑填入其中。如下所示。
打開cmd輸入 mongo命令,驗證是否成功,成功效果如下:
MongoDB使用
服務端啓動
MongoDB數據庫是使用文件形式存儲的(可以用U盤拷貝走,好神奇),因此必須先新建一個文件夾,用來存放數據庫。比如 E:\4.臨時文件\mongo_db_dir
,新建完成後可使用mongod命令來啊開啓數據庫服務:
mongod --dbpath E:\4.臨時文件\mongo_db_dir
- mongod 是MongoDB啓動命令
- –dbpath是指定數據庫文件存放位置,後邊是路徑
如下:
客戶端連接
執行
mongo 127.0.0.1:27017
- mongo 是客戶端啓動命令
- 127.0.0.1:27017 是MongoDB數據庫服務端的IP地址和端口
成功連接的截圖如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳
數據庫操作
查看所有數據庫列表
在mongo shell中執行:(本文下面命令均爲mongoshell命令)
show dbs
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳
創建數據庫
MongoDB中集合相當於mysql中的表,文檔相當於mysql中的行。
創建數據庫和使用數據庫是同一個命令
use student
- use 是選擇命令(也是新建命令)
- student 是數據庫名稱
與mysql不同的是,MongoDB數據庫創建成功後必須向其中插入一條數據,否則創建失敗。
插入數據
而數據庫不能直接插入數據,數據只能插入到集合(表)中,使用命令:
db.student.insert({"name":"zhangsan"})
-
db 默認值,代表當前選中的數據庫。
-
student 是集合名稱。
-
mongoDB中插入的數據是json格式,{“name”:“張三”}是插入的數據。
上述命令執行後,系統發現student沒有這個集合,因此自動創建改集合(表)
執行結果:
查看所有集合(表)
查看當前選擇數據庫中的所有集合,執行:
show collections
刪除集合(表)
db.student.drop()
- db 當前選中數據庫
- student 要刪除的集合名稱
- drop() 刪除命令
結果如下:
刪除數據庫
db.dropDatabase();
- dropDatabase() 刪除命令
查詢數據
1. 查詢所有記錄
db.user.find() //等同於 select * from user;
- user 是集合名稱,(表名稱)
- find() 查詢操作
2. 過濾某列重複數據
db.user.distinct("name"); //等同於 select distict name from user;
- user 集合名稱
- distinct 過濾查詢
3. 條件查詢
a. 查詢 age=27的記錄
db.user.find({"age":27}) //等同於 select * from user where age = 27;
b. 查詢 age>27的記錄
db.user.find({age:{$gt:22}}) //等同於 select* from user where age >22;
- $gt 表示大於
c. 查詢 age<27 的記錄
db.user.find({age:{$lt:27}}) //等同於 select * from user wwhere age < 27;
- $lt 表示小於
d. 查詢 age>= 27 的記錄
db.user.find({age:{$gte:27}}) //等同於 select * from user where age >= 27;
- $gte 表示大於等於
- $lte 表示小於等於
e. 查詢 age>=23 並且 age<=26 的記錄
db.user.find({age:{$gte:23,$lte:26}})
結果如下:
f: 查詢name中含有mongo 的數據 (模糊查詢用於搜索)
db.user.find({name:/mongo/}) //等同於 select * from user where name like '%mongo%';
- db 當前選擇的數據庫
- user 集合(表)
- find({name:/mongo/}) 查詢集合(表)中name包含mongo的記錄,侯彪的//應該是正則
g: 查詢name中以iam 開頭的金雞路
db.user.find({name:/^iam/}) //等同於 select * from user where name like `mongo%`;
結果如下:
h:查詢指定列 name 和 age 的數據
db.user.find({},{name:1,age:1}); //相當於select name,age from user;
- find({},name:1,age:1) 前一個{} 是搜索條件,後一個{}是顯示字段,其中1,亦可以使用true或者false,如果爲false,那麼就是排除指定字段,顯示其他字段。
i: 查詢指定列 name,age,並限定age>25
db.user.find({age:{$gt:25},{name:true,age:true}}) //相當於 select name,age from user where age>25;
j: 按照年齡排序 1 升序 -1降序
db.user.find().sort({age:1}) //升序
db.user.find().sort({age:-1}) //降序
k: 查詢name=張三,age=22 的數據
db.user.find({name:"zhangsan",age:22}) //等同於 select * from user where name = 'zhangsan' and age = '22';
l: 查詢前5條數據
db.user.find().limit(5) //等同於 selecttop 5 * from user;//不確定,,,
m: 查詢10條以後的數據
db.user.find().skip(10); //相當於 select * from user where id not in (selecttop 10 * from user) //不確定沒試過mysql此條。。
n:查詢 5-10 之間的數據
db.user.find().limit(10).skip(5);
這條查詢命令可以用於分頁,比如limit 是pagesize,skip是第幾頁*pagesize
比如每頁5條,我要查看第三頁的數據,那麼有
db.user.find().limit(5).skip(10)//5是每頁條數,10是2*5,要跳過的條數
o:條件 或 查詢 查詢age=22或者=29 的記錄
db.user.find({$or:[{age:22,{age:29}]}) //等同於 select * from userwhere age=22 or age = 25;
p: 查詢第一條數據
db.userinfo.findOne(); //等於於db.userinfo.find().limit(1) //等同於 selecttop 1 * from user;//不確定
q:查詢結果集中的總記錄條數, 用於統計數量
db.user.find({age:{$gte:25}}).count(); //相當於 select count(*) from userinfo where age>=20;
修改更新數據
a. 更改部分字段(字段不準確,應該是更改部分屬性):
db.user.update({name:"liming"},{$set:{age:16}})
- update 更新數據的命令,前一個對象是檢索條件,檢索name是liming的記錄,後一個對象{$set:{age:16}} 要更改爲的數據
整個語句的作用是修改屬性name爲liming的對象中的age爲16,執行結果如下:
默認情況下update
操作是匹配單個document(記錄)要匹配所有記錄,需要在update方法中增加一個{multi:true}對象
db.user.update({sex:"man"},{$set:{age:18}},{multi:true});
b. 如果是對doucment,也就是記錄進行完全修改,那麼就不能出現$set
關鍵字了
比如修修改name=lisi的對象所有屬性爲{name:lisi2,age:100}
db.user.update({name:"lisi"},{name:"lisi2",age:100})
c. 複雜修改,爲指定記錄的age增加20歲
db.user.update({name:"lisi2"},{$inc:{age:10}},false,true) //這條沒有驗證成功!
爲name等於lisi2的記錄 屬性age增加10
錯誤截圖
提示沒有選中。。爲什麼???
刪除數據
db.user.remove({name:"lisi2"})
- user 集合名稱
- remove 刪除方法,參數對象是要刪除document的檢索條件。
注意:與update不同的是remove操作默認將刪除所有匹配記錄,如果要刪除第一個條匹配的記錄(document),操作方法中增加{justOne,true}對象
如下:
db.user.remove({name:"lisi2"},{justOne:true});
索引
針對關係型數據庫,索引是對數據庫表中一列或者多列的值進行排序的一種結構,可以然我們查詢數據庫變得更快。而MongoDB索引與關係型數據庫相似,建立索引也能加快查詢速度。
基本命令
爲演示索引建立前後的查詢速度對比,可以在MongoDB客戶端shell中使用js語法創建一個大數據量的集合 teacher。建集合(表)命令如下:
for(var i = 0; i < 655360; i++){
db.teacher.insert({name:"teacher"+ i,age:Math.ceil(Math.random()*100),sex: Math.random()>0.5?"man":"woman"})}
}
運行結果是:(因爲要插入65萬條數據,數據量大命令執行時間長,耐心等待)
1. explain 工具
explain 命令能夠顯示查詢語句的相關信息,包括查詢索引情況、耗時以及掃描文檔數等統計信息。
db.teacher.find({name:"teacher456780"}).explain()
這裏我們暫時關注查詢耗時,用來驗證索引加上前後的不同。
db.teacher.find({name:"teacher456780"}).explain("executionStats")
2. 查詢索引
db.teacher.getIndexes()
默認只有一個索引:_id,(關注key)
3. 創建索引
db.teacher.ensureIndex({name:1})
- teacher 是創建索引的集合名稱
- ensureIndex({name:1}) ensureIndex是創建索引命令,name是 要創建索引的屬性(字段)其中1表示對name進行升序排序,-1 表示對name進行降序排序
索引創建成功。
4. 刪除索引
db.teacher.dropIndex({name:1})
5. 驗證索引作用
爲了驗證索引對於查詢速度的作用,可以在teacher集合中根據name屬性查詢一條記錄,記錄查詢時間,然後爲name建立索引後再次查詢,記錄插敘時間,對比兩者查詢時間。
未建立索引查詢截圖
建立索引後查詢截圖
可以看出未對name屬性建立索引對name屬性進行查詢時耗時968ms,而建立後僅僅耗時3ms,因此來看索引加快查詢速度是真的!
6. 複合索引
符合索引是多一個集合中多個屬性(一個表中多個字段)同時建立索引,比如:
db.teacher.ensureIndex({name:1,age:-1})
- 爲teacher集合建立name與age的符合索引,name升序排列,age降序排列。
複合索引創建後,對name與age的查詢會用到索引,另外對於前一個name的查詢,也會要到,但是對age的查詢就不可以了。所以要使用符合索引,必須在查詢條件中包括符合索引的前N個索引屬性,最後一個索引屬性不能用。
可以看出對符合索引中前n個(1)字段name索引,可以使用符合索引,加快查詢速度,對符合索引最後一個字段age進行查詢,不能使用符合索引,所以耗時仍然與未建立索引保持一致,耗時時間長。
注意:對大數據量的集合中的無索引元素進行排序時,需要把所有數據提取到內存中,有可能導致爆內存,導致MongoDB報錯。
7. 唯一索引
唯一索引的作用是保證集合(表)中對建立索引的字段保證唯一性,比如對id建立唯一索引,那麼這個集合就不可以出現相同id的document(記錄)。默認創建的索引不是唯一索引,建立唯一索引的命令如下:
db.user.ensureIndex({name:1},{unique:true})
- unique:true 表示建立唯一索引
唯一索引建立後,再次插入相同內容的name屬性會報錯。
如果插入新的document(記錄)不包含唯一索引字段時,MongDB默認將其置爲null,如果多次插入相同的內容,null也會受到唯一索引限制,報錯。
對於一個沒有建立唯一索引,但是存在字段數據重複的document(記錄)時,建立唯一索引會報錯
符合索引也可以建立唯一索引
db.teacher.ensureIndex({name:1,age:-1},{unique:true})