算是學習下來精煉的筆記,希望對大家有幫助。如果有問題歡迎大家指正。
0.概述
MongoDB 是由C++語言編寫的,是一個基於分布式文件存儲的開源數據庫系統。
在高負載的情況下,添加更多的節點,可以保證服務器性能。
MongoDB 旨在為WEB應用提供可擴展的高性能數據存儲解決方案。
MongoDB 將數據存儲為一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔類似於 JSON 對象。字段值可以包含其他文檔,數組及文檔數組。
下面是與sql概念的對比。能夠幫助我們更好的理解mongodb。
SQL術語/概念 | MongoDB術語/概念 | 解釋/說明 |
---|---|---|
database | database | 數據庫 |
table | collection | 數據庫表/集合 |
row | document | 數據記錄行/文檔 |
column | field | 數據字段/域 |
index | index | 索引 |
table joins | 表連接,MongoDB不支持 | |
primary key | primary key | 主鍵,MongoDB自動將_id字段設置為主鍵 |
總結下來,傳統的關系型數據庫的內容結構是
- 數據庫
- 表
- 行
- 字段
Mongodb與之對應的就是
- 數據庫
- 集合
- 文檔
- 域
1.brew安裝
不推薦用brew,因為現在mongodb閉源了,brew里已經搜索不到mongodb,不過還是可以用brew安裝的,這篇就不寫了。
2.官網下載
直接去官網下載一個zip,解壓完放到usr/local/里(control+shift+。可以顯示隱藏文件夾),改名為mongodb。
然后添加一個環境變量就可以用了
$ export PATH=/usr/local/mongodb/bin:$PATH
這樣就添加好了,反正就是現在可以用了。
可以用mongo來測試是否安裝好了,如果都弄好了應該會彈出版本。
3.創建data/db文件夾
接下來就是新建data/db然后運行mongodb的步驟了。
不過mac os catalina現在有問題,跟目錄不讓寫東西了,所以要曲線救國,根據mongodb給的最新的解決辦法就是在/Users/(你的用戶名)/data/db/
里當目錄了
最后帶上--dbpath= ,如果不添加會默認到/data/db里
sudo mongod --dbpath=/Users/Wangzirui/data/db
如果不是卡特琳娜那好說,
sudo mkdir -p /data/db
然后 sudo mongod
就完事了。
更改catelina限制之后(關閉sip)。可以直接用 sudo mount -uw / 更改跟目錄權限,就可以直接sudo mongod就完事了。
然后另一個終端進入/usr/loacl/mongodb/bin/
然后./mongo就啟動了mongo的客戶端
或者直接mongo也可以。
4.開啟服務創建客戶端
啟動服務:
sudo mount -uw /
sudo mongod
啟動客戶端:
mongo
5.命令
5.1 db操作
-
顯示數據庫
- show dbs
-
切換數據庫,沒有就新建一個
- use admin
-
顯示你在哪個數據庫里
- Db
-
刪除當前你use的那個數據庫
- db.dropDatebase()
-
新建數據庫
- use 數據庫名字
- 建完了show dbs不會立刻顯示,因為剛才新建的數據庫里面沒有數據。所以顯示不出來。
5.2 collection操作
-
顯示這個數據庫中有什么集合
- show collections
-
新建集合,在use 一個數據庫的情況下
- db.createCollections(name,options)
- 然后show dbs現在可以看到use的數據庫了
-
刪除集合 ,在現在這個Use的數據庫的情況下
- db.你想要的collectionname.drop()
- 然后就刪掉了
5.3 document操作
collectionname代指相對應的collcetion名字(mysql里叫表,Mongodb里叫collection,都是一個數據庫里的一種結構) 現在操作的不是表也不是集合,而是集合里的一個數據結構叫做document,文檔,文檔相當於mysql里的一個記錄行。
-
往collection里加數據,直接新建document
- db.collectionname.insert({"name":"wangzirui"})
- 增加多條要在insert的多個對象的外面加一個中括號,表示這是一個對象數組。
- db.collectionname.insert([{name:"wangzirui"},{name:"laoli"}])
-
查看collection里的數據
- db.collectionname.find()
-
Save,在_id一樣的情況下可以不報錯,然后直接覆蓋掉剛才重復Id的內容。
- db.collectionsname.save({_id:1001,name:"laowang",age:22})
-
更新document數據
- db.collectionname.update({當前數據},{替換數據},{配置項})
- db.collectionname.update({name:"laotie"},{name:"ergou"})
- 這樣會刪除其他內容,只存在一個name :ergou 所以要加$set保留其他的參數
- db.collectionname.update({name:"laotie"},{$set:{name:"ergou"}})
- 配置項里加{Multi:true}加一個這個的話可以讓多個name:"laotie"一起改
- db.collectionname.update({name:"laotie"},{$set:{name:"ergou"}},{multi:true})
-
刪除document內容,如果不加第二個參數,默認是把集合里的符合第一條的都刪掉。
- Db.collectionname.remove({name:"laotie"},{justOne:true})
5.4 document 查詢
經過上面的講述,能了解到一點,基於database來查詢collections里的數據都是通過db.collcetion_name.方法 來進行操作的,同理。對document的查詢,我們之前也在查看collection時用過,他就是find()方法。
find里面可以加參數,不加的話就是現實collection里所有的document。
-
find()方法里可以加條件,例如db.collectionname.find({age:18})
- 如果一行一行的話不好看,可以再db.collectionname.find({age:18})后面加.pretty()
-
比較運算符
- less than 小於 $lt db.collection_name.find(age:{$lt:18})
- less than equal 小於等於 $lte
- Geater than 大於 $gt
- $gte 大於等於
- $ne 不等於
-
取范圍內的 $in
- $in:[10,20,30]
- db.collection_name.find({age:{$in:[10,20,30]}})
-
並操作
- db.collection_name.find(age:18,name:"laotie")
-
或操作
- db.collection_name.find({$or:[{age:18},{name:"laotie"}]}
-
正則
- db.collection_name.find({age:/1/})或者db.collection_name.find({age:$regex:"1"})
-
限制和跳過,一般用於分頁
- limit(2)
- skip(2)
-
投影
- 比如說find({這里放具體參數},{這里放投影})
- db.collection_name.find({age:{$lt:18}},{_id:0,age:1}) 這樣只會顯示每個對象里面只有一個age選項了
- 注意,如果投影里不加_id的選項的話 ,默認是自動顯示的。只能給_id設置 0。如果別的字段不想讓他顯示直接不在里面加。其他的想要顯示的話直接把屬性加進去就行了。
-
通過Js函數來篩選數據
-
$where:
-
db.collection_name.find({$where:function(){
Return age>10}})
-
-
根據某個字段排序
- sort
- db.collection_name.find().sort({age:1}) 如果降序的話要帶-1
-
計數
-
count()
-
直接在查詢出來的后面加上就可以顯示了
-
db.collection_name.find({$where:function(){
Return age>10}}).count()
-
-
去重
- db.student.distinct("name",{"age" : 18})
- 這樣可以直接把name一樣還有age為18的都給去重
6.備份和恢復
6.1備份
直接在終端輸入,不要在mongodb的客戶端輸入
mongodump -h hostname -d dbname -o dbdirectory
-h 服務器地址,可以指定端口號。本機可以不填
-d 具體Mongodb下哪個數據庫
-o 你想保存到本地的什么地方
例如本機 下在termainal直接輸入 mongodump -d laotie -o wenjianjia
然后就把 laotie這個數據庫保存到Users/wangzirui/wenjianjia這個文件夾里了
6.2恢復
同樣直接在終端輸入
Mongorestore -h hostname -d dbname --dir
-h 服務器地址,可以指定端口號。本機可以不填
-d 你想讓這個數據庫叫什么,不一定是原名
-Dir 這個備份文件在哪里
7.聚合
aggregate,就是一個管道,類似中間件或者是函數的鏈式調用。最終導出想要的數據。
7.1group
首先放一個student集合的數據,聚合所有的操作都是按照這些數據來的。
> db.student.find()
{ "_id" : ObjectId("5e003b92f197cb08dc74a311"), "name" : "duanyuxin", "age" : 21, "sex" : "male" }
{ "_id" : ObjectId("5e003b92f197cb08dc74a312"), "name" : "baiyu", "age" : 20, "sex" : "male" }
{ "_id" : ObjectId("5e003f66f197cb08dc74a313"), "name" : "wangzirui", "age" : 22, "sex" : "male" }
{ "_id" : ObjectId("5e003f8ff197cb08dc74a314"), "name" : "zhuhuan", "age" : 22, "sex" : "female" }
{ "_id" : ObjectId("5e003f8ff197cb08dc74a315"), "name" : "caoyajing", "age" : 12, "sex" : "female" }
先放例子:
> db.student.aggregate({
$group:{_id:"$sex",avg_age:{$avg:"$age"}}
})
{ "_id" : "male", "avg_age" : 21 }
{ "_id" : "female", "avg_age" : 17 }
在$group
的對象里,前面開頭的域(字段)代表下面將要輸出的域的值。 后面的$sex
表示的是我拿什么東西當做group分組的鍵值。如果我針對不同的age分組,那么我將會得到
> db.student.aggregate({
$group:{_id:"$age"}
})
{ "_id" : "12"}
{ "_id" : "20"}
{ "_id" : "21"}
{ "_id" : "22"}
的結果。
接着說avg_age,這個域是我們自己定義的。(可能是先入為主,我總覺得說字段更為適應,大家也更容易理解),叫什么都行,但是后面$avg:"$age"
的意思就是,首先前面$avg
就是取平均值,取得就是你后面$age
的平均值。然后輸出的時候就打印"avg_age:前面符合id分類的文檔的age平均值"
如果想計算整個文檔的某些值,僅需要把_id:null
然就可以不分組,直接用整個文檔來算。
> db.student.aggregate({
$group:{_id:null,avg_age:{$avg:"$age"}}
})
{ "_id" : null, "avg_age" : 19.4 }
$sum:
另外講一個$sum的用法,先看怎么用。
> db.student.aggregate({
$group:{_id:null,count:{$sum:1},avg_age:{$avg:"$age"}}
})
{ "_id" : null, "count" : 5, "avg_age" : 19.4 }
在剛才的基礎上加了一個$sum:1
里 $sum
顧名思義是求和用的,后面是求和的倍數,如果你設成2的話結果就乘2變成10.一般用來計數的話普遍還是設置成1的。
利用$group去重:
$group
不止可以添加一個分組條件,也可以添加多個分組條件,如果把每個條件都對應文檔的域,那么就相當於去重操作。
> db.student.aggregate({
$group:{_id:{name:"$name",sex:"$sex",age:"$age"}}
})
然后接下來用別的通道來進行下一步的操作就可以了。但是接下來的操作要用到的屬性就是$_id.name
類似的。因為我們去重時把屬性都給了叫_id的域。
7.2$project
重構輸出結構,也就是在aggregete的通道特性,然在最后調整你想要的輸出結構。大體上和投影類似。
放栗子:
> db.student.aggregate(
{
$group:{_id:null,count:{$sum:1},avg_age:{$avg:"$age"}}
},
{
$project:{sex:"$_id",count:"$count",avg_age:"$avg_age"}
}
)
{ "_id" : null, "sex" : null, "count" : 5, "avg_age" : 19.4 }
同理,可以用1 或者0代替。具體不舉例子了,沒什么大用。
7.4 $match
聽名字就知道是過濾用的,雖然find同樣可以過濾,但是不能將find出來的結果傳給下一個管道。
比如說你想呀知道年齡大於20的男生和女生分別有幾個人
可以按照下面的方式操作
db.student.aggregate(
{$match:{age:{$gt:19}}},
{$group:{_id:"$sex",count:{$sum:1}}},
{$project:{_id:0,sex:"$_id",count:1}}
)
{ "count" : 3, "sex" : "male" }
{ "count" : 1, "sex" : "female" }
大體就是這樣,里面填的東西和find里是差不多的。
7.5 $sort
用法跟普通的用法一致,直接放栗子:
db.student.aggregate(
{$group:{_id:"$sex",count:{$sum:1}}},
{$sort:{age:1}}
)
{ "_id" : "female", "count" : 2 }
{ "_id" : "male", "count" : 3 }
如果前面的其他方法都看懂了,這個應該不成問題。就不解釋了。
7.6 $limit,skip
同樣跟前面很像,直接放例子:
db.student.aggregate(
{$skip:2},{$limit:2}
)
{ "_id" : ObjectId("5e003f66f197cb08dc74a313"), "name" : "wangzirui", "age" : 22, "sex" : "male" }
{ "_id" : ObjectId("5e003f8ff197cb08dc74a314"), "name" : "zhuhuan", "age" : 22, "sex" : "female" }
不解釋了。
8.創建索引
for(i=0;i<100000;i++){db.test.insert({name:'test'+i,age:i})}
在數據量特別龐大的時候,尋找數據就會變得慢一點。
所以要針對性的給集合建立索引
db.test.ensureIndex({name:1})
然后這個集合就有兩個索引了,之前那個索引叫_id,現在添加了一個域name也作為索引。
關於索引的幾個操作:
- 創建唯一索引
- db.test.ensureIndex({name:1},{uniqe:true})
- 建立聯合索引
- db.test.ensureIndex({name:1},{age:1})
- 查看當前集合的索引
- db.test.getIndexes()
- 刪除索引
- db.t1.dropIndex("索引名")