MongoDB 是一種NoSQL 數據庫,本文主要介紹MongoDB裏面的一些基本概念和操做、以及可視化工具的安裝和使用。html
做者:奔放的辣條妹
閱讀時間大約 20min+java
MongoDB 是一種NoSQL 數據庫,存儲的數據對象由鍵值對組成。MongoDB 全部存儲在集合中的數據都是 BSON 格式。BSON 是一種相似 JSON 的二進制形式的存儲格式,是 Binary JSON 的簡稱。以下所示:python
{
"_id" : ObjectId("5c89f787ca6e4e3ac1ecabkk"),
"_plat" : "test_plat0",
"update_time" : ISODate("2019-06-03T15:00:42.142Z"),
"create_time" : ISODate("2019-03-14T14:41:11.217Z"),
"creator" : "test_user",
"admin" : [
"admin1",
"admin2"
],
"ops" : [
"ops1"
],
"labels" : {
"department" : "departmentA",
"main_class" : "mainClassA"
}
}
複製代碼
下面對照關係型數據庫介紹一些 MongoDB 裏面的基本概念:c++
關係數據庫術語 | MongoDB術語 | 說明 |
---|---|---|
database | database | 數據庫 |
table | collection | 數據庫表/集合 |
row | document | 記錄行/文檔 |
column | field | 數據字段/域 |
index | index | 索引 |
primary key | primary key | 主鍵,Mongodb自動將_id字段設置爲主鍵 |
經過如下對比能夠更理解 MongoDB :sql
id | 姓名 | 年齡 | 性別 |
---|---|---|---|
1 | 張三 | 23 | 男 |
2 | 李四 | 21 | 男 |
上述關係型數據在 MongoDB 中的數據形式爲:mongodb
{
"_id" : ObjectId("5c89f787ca6e4e3ac1ehhb23"),
"姓名" : "張三",
"年齡" : 23,
"性別" : "男"
}
{
"_id" : ObjectId("5c89f787ca6e4e3ac1ehhb24"),
"姓名" : "李四",
"年齡" : 21,
"性別" : "男"
}
複製代碼
本節主要介紹經過命令行操做 MongoDB,以 MongoDB 安裝在 CentOS 上爲例進行說明。數據庫
DB 的查看、建立、刪除,集合的查看、建立、刪除等操做方式以下:json
[root] mongo #命令行輸入mongo進入MongoDB命令交互模式
> show dbs #列出已有db
> use my_db #若是my_db存在,則切換到my_db,若是不存在,則建立之
> db #顯示當前db
> show dbs #發現列表裏面沒有my_db,由於此時db裏面沒有實際數據或者集合哦
> db.createCollection("my_col") #建立集合my_col
> db.my_col_new.insert({"name":"測試一下"}) #往集合my_col_new裏面插入一條數據,若是集合不存在,會自動建立
> show collections #列出改db下面全部的集合
> show tables #功能跟show collections是同樣的哦
> db.my_col.drop() #刪除集合my_col
> db.dropDatabase() #刪除當前數據庫,執行以前用db命令確認一下當前數據庫是否是你要刪除的這個哦
複製代碼
插入數據有4種方法:insert、insertOne、insertMany、save,下面經過例子詳細介紹。數組
> db.my_col.insert({"name":"xiaoming"}) #insert能夠插入一條數據
> db.my_col.insert([{"name":"xiaoming"},{"name":"test_user"}]) #insert也能夠插入多條數據
> db.my_col.insertOne({"name":"xiaoming"}) #insertOne只能插入一條數據
> db.my_col.insertMany([{"name":"xiaoming"}]) #insertMany能夠插入一條或多條數據,可是必須以列表(list)的形式組織數據
> db.my_col.save([{"name":"xiaoming"},{"name":"test_user"}]) #若是不指定_id,save的功能與insert同樣
> db.my_col.save({"_id":ObjectId("5d07461141623d5db6cd4d43"),"name":"xiaoming"}) #若是指定_id,mongodb就不爲該條記錄自動生成_id了,只有save能夠指定_id,insert、insertOne、insertMany都不能夠
複製代碼
修改數據有2種方法:update、save,下面詳細介紹。bash
首先,看一下 update 的語法格式,請格外注意一些可選參數的值,這將直接影響你的修改結果:
db.collection.update(
<query>, #update的查詢條件,相似sql update語句where後面的部分
<update>, #update的對象和一些更新的操做符等,也能夠理解爲sql update語句set後面的
{
upsert: <boolean>, #可選,這個參數的意思是,若是不存在update的記錄,是否插入objNew,true爲插入,默認是false,不插入
multi: <boolean>, #可選,mongodb 默認是false,只更新找到的第一條記錄,若是這個參數爲true,就把按條件查出來多條記錄所有更新
writeConcern: <document> #可選,拋出異常的級別
}
)
複製代碼
假設有這樣一張學生成績表:
> db.my_col.insert([{"name":"xiaoming","class":"c++", "score":60},{"name":"xiaoming","class":"python", "score":95}])
> db.my_col.find().pretty()
{
"_id" : ObjectId("5d0751ef41623d5db6cd4d44"),
"name" : "xiaoming",
"class" : "c++",
"score" : 60
}
{
"_id" : ObjectId("5d0751ef41623d5db6cd4d46"),
"name" : "xiaoming",
"class" : "python",
"score" : 95
}
複製代碼
xiaoming 同窗發現老師把她的 c++ 課程分數錄錯了,須要修改成75分:
> db.my_col.update({"_id":ObjectId("5d0751ef41623d5db6cd4d44")},{$set:{"score":75}})
複製代碼
老師發現把 xiaoming 同窗的名字錄錯了,須要所有修改過來:
> db.my_col.update({"name":"xiaoming"},{$set:{"name":"xming"}}) #這樣是不對的,只會修改一條記錄
> db.my_col.update({"name":"xiaoming"},{$set:{"name":"xming"}},{multi:true}) #這樣纔對
複製代碼
將 xming 的 java 課程分數改成95分,若是找不到,就插入一條記錄
> db.my_col.update({"name":"xming", "class": "java"},{$set:{"score": 95}},true)
複製代碼
save 方法經過傳入的文檔來替換已有文檔。語法格式以下:
db.collection.save(
<document>, #文檔數據
{
writeConcern: <document> #可選,拋出的異常級別
}
)
複製代碼
還以上面那張學生成績表爲例:
> db.my_col.save({
"_id" : ObjectId("5d0751ef41623d5db6cd4d44"), #指定_id,新的文檔會將舊的文檔覆蓋
"name" : "xming",
"class" : "c++",
"score" : 80
})
複製代碼
數據刪除可使用 deleteOne、deleteMany、remove,下面詳細介紹。
使用方法以下:
> db.my_col.deleteOne({"name":"xming"}) #刪除xming的一條成績記錄
> db.my_col.deleteMany({"name":"xming"}) #刪除xming的全部成績記錄
> db.my_col.deleteMany({}) #刪除成績表裏面的全部內容
複製代碼
首先仍是來看語法格式:
db.collection.remove(
<query>, #可選,查詢條件
{
justOne: <boolean>, #可選,設置爲true或者1,表示只刪除一個文檔,設置爲false,表示刪除全部匹配的文檔,默認爲false
writeConcern: <document> #可選,拋出異常的級別
}
)
複製代碼
刪除 xming 的全部成績記錄:
> db.col.remove({"name":"xming"})
> db.repairDatabase() #remove方法並不會真正釋放空間,須要繼續執行 db.repairDatabase() 來回收磁盤空間
> db.runCommand({ repairDatabase: 1 }) #與上一句等效,仍以執行一句便可
複製代碼
ps:remove 如今已通過時瞭如今官方推薦使用 deleteOne 和 deleteMany 方法。
數據查詢的方法有 findOne 和 find,兩者參數等用法同樣,可是 findOne 只返回一條匹配的數據,find 返回所有的匹配數據,下面主要介紹 find 的用法。
操做 | sql查詢寫法 | mongo查詢寫法 |
---|---|---|
等於 | select * from my_col where score = 75; | db.my_col.find({"score": 75}).pretty() |
小於 | select * from my_col where score < 75; | db.my_col.find({"score": {$lt: 75}}).pretty() |
小於等於 | select * from my_col where score <= 75; | db.my_col.find({"score": {$lte: 75}}).pretty() |
大於 | select * from my_col where score > 75; | db.my_col.find({"score": {$gt: 75}}).pretty() |
大於等於 | select * from my_col where score >= 75; | db.my_col.find({"score": {$gte: 75}}).pretty() |
不等於 | select * from my_col where score != 75; | db.my_col.find({"score": {$ne: 75}}).pretty() |
ps:pretty 能讓查詢結果以格式化的 json 形式打印出來,便於查看
以分數從高到低顯示學生的 c++ 課程成績,只顯示第10名到第20名的學生:
> db.my_col.find({"class": "c++"}).sort({"score": -1}).skip(9).limit(11).pretty()
#sort:1爲升序,-1爲降序,默認升序
#limit:顯示多少條數據
#skip:跳過多少條數據
複製代碼
and:find 方法能夠傳入多個鍵值對,每一個鍵值對以逗號隔開,即常規 SQL 的 AND 條件
查詢 xiaoming 同窗的 c++ 課程成績:
> db.my_col.find({"name": "xiaoming", "class": "c++"}).pretty()
複製代碼
查詢分數在75到85分之間的成績記錄:
> db.my_col.find({"score": {$gt: 75, $lt: 85}}).pretty()
複製代碼
or:MongoDB OR 條件語句使用了關鍵字 $or,語法格式以下:
> db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
複製代碼
查詢 xiaoming 或 zhangsan 的課程成績:
> db.my_col.find({$or: [{"name": "xiaoming"}, {"name": "zhangsan"}]}).pretty()
複製代碼
and + or 複合查詢:
查詢 xiaoming 的 c++ 或者 python 課程的成績:
> db.my_col.find({"name": "xiaoming", $or: [{"class": "c++"}, {"class": "python"}]}).pretty()
複製代碼
查詢 xiaoming、zhangsan 和 lisa 的成績:
> db.my_col.find({"name": {$in: ["xiaoming","zhangsan","lisa"]}}).pretty()
複製代碼
查詢除了 xiaoming、zhangsan 和 lisa 以外,其餘人的成績:
> db.my_col.find({"name": {$nin: ["xiaoming","zhangsan","lisa"]}}).pretty()
複製代碼
in和nin比較好理解,跟sql的用法相似,all相似於in,不一樣的地方是,in只須要知足列表中的一個值便可,而all須要知足列表中的所有值。好比,有下面這樣一張課程表,表示每一個學生修的課程:
> db.course.find().pretty()
{
"_id" : ObjectId("5d084f1541623d5db6cd4d4c"),
"name" : "xiaoming",
"course" : [
"c++",
"python",
"java"
]
}
{
"_id" : ObjectId("5d084f1c41623d5db6cd4d4d"),
"name" : "lisa",
"course" : [
"c++",
"python",
"java"
]
}
{
"_id" : ObjectId("5d084f4a41623d5db6cd4d4e"),
"name" : "tom",
"course" : [
"c++",
"python"
]
}
複製代碼
須要找出修了 c++ 和 java課程的學生:
> db.course.find({"course": {$all: ["c++", "java"]}}).pretty() # 用 all 操做符,表示須要知足 c++ 和 java 兩項
複製代碼
好比,有下面一張表,表示學生信息:
> db.stu_info.find().pretty()
{
"_id" : ObjectId("5d08519a41623d5db6cd4d4f"),
"name" : "xiaoming",
"tel" : "138xxxxxxxx"
}
{
"_id" : ObjectId("5d08531641623d5db6cd4d50"),
"name" : "lisa"
}
{
"_id" : ObjectId("5d08542e41623d5db6cd4d51"),
"name" : "tom",
"tel" : null
}
複製代碼
須要找出沒有 tel 字段的學生:
> db.stu_info.find({"tel": {$exists: false}}).pretty() #字段不存在就用false,存在就用true
複製代碼
以上面的學生信息表爲例,找出 tel 爲空值的學生:
> db.stu_info.find({"tel": null}).pretty()
{
"_id" : ObjectId("5d08531641623d5db6cd4d50"),
"name" : "lisa"
}
{
"_id" : ObjectId("5d08542e41623d5db6cd4d51"),
"name" : "tom",
"tel" : null
}
複製代碼
這時候把 tel 字段不存在和 tel 值爲 null 的狀況都查出來了!若是隻想找 tel 值爲 null 的狀況:
> db.stu_info.find({"tel": {$in:[null], $exists:true}}).pretty()
複製代碼
好比,查找學生成績取模10 等於0 的數據(即100、90、80...等等):
> db.my_col.find({"score": {$mod: [10, 0]}}).pretty()
複製代碼
查詢學生名字以a開頭的學生成績:
> db.my_col.find({"name": {$regex: /^a.*/}})
複製代碼
獲取學生成績記錄的條數:
> db.my_col.find().count()
複製代碼
當使用 limit 方法限制返回的記錄數時,默認狀況下 count 方法仍然返回所有記錄條數。若是但願返回限制以後的記錄數量,要使用 count(true) 或者 count(非0):
> db.my_col.find().count()
4
> db.my_col.find().limit(1).count()
4
> db.my_col.find().limit(1).count(true)
1
複製代碼
查詢課程成績表中全部學生的名單:
> db.my_col.distinct("name")
複製代碼
在MongoDB中,使用聚合框架能夠對集合中的文檔進行變換和組合,完成一些複雜的查詢操做。聚合框架經過多個構件來建立一個管道(pipeline),用於對一連串的文檔進行處理。這些構件包括但不限於:
操做符 | 意義 |
---|---|
$match | 篩選 |
$project | 投射,選擇想要的字段或對字段進行重命名 |
$group | 分組 |
$unwind | 拆分 |
$sort | 排序 |
$limit | 限制查詢條數 |
$skip | 跳過一些條數 |
當須要使用多個操做符來完成文檔的聚合時,咱們能夠傳入一個數組條件,這也是aggregate的常見用法:
> db.my_col.aggregate([
{$match: {"name": "xiaoming"}}, #查找 xiaoming 同窗的課程成績
{$project: {"_id": 0}}, #不須要_id字段
{$sort: {"score": -1, "class": 1}}, #按分數降序排序;一樣分數的,按課程名字升序排序
{$skip: 1}, #跳過一條數據
{$limit: 1} #只顯示一條數據
])
複製代碼
$match用於對文檔集合進行篩選,以後就能夠在篩選獲得的文檔子集上作聚合。"$match"可使用全部常規的查詢操做符("$gt"、"$lt"、"$in"等)。一般,在實際使用中應該儘量將"$match"放在管道的前面位置。這樣作有兩個好處:一是能夠快速將不須要的文檔過濾掉,以減小管道的工做量;二是若是在投射和分組以前執行"$match",查詢可使用索引。
$project能夠從子文檔中提取字段,能夠重命名字段。例如,查找學生課程成績,不顯示 _id 字段,顯示姓名、課程、成績字段,同時將 name 字段重命名爲 student_name:
> db.my_col.aggregate([
{$project: {"_id": 0, "student_name": "$name", "core": 1, "class": 1}}
])
複製代碼
$sort、$skip、$limit 的用法比較好理解,就很少作說明。
$group 相似於 sql 中的 group by,主要用於數據處理,好比,計算每一個學生的總課程成績:
> db.my_col.aggregate([
{$group: {_id: "$name", total: {$sum: "$score"}}}
])
複製代碼
$sum 能夠 替換成操做符 $avg、$min、$max,分別表示求平均成績、最低成績、最高成績。
$unwind 能夠將數組中的每個值拆分爲單獨的文檔,好比有下面一條記錄,記錄了一篇博客以及下面的評論:
> db.blog.findOne().pretty()
{
"_id":ObjectId("5359f6f6ec7452081a7873d7"),
"title":"這是一篇博客",
"auth":"xiaoming",
"comments":[
{
"author":"lisa",
"date":ISODate("2019-01-01T17:52:04.148Z"),
"text":"Nice post"
},
{
"author":"tom",
"date":ISODate("2019-01-01T17:52:04.148Z"),
"text":"I agree"
}
]
}
複製代碼
如今要找到 lisa 的評論,能夠先使用 $unwind 將每條評論拆分爲一個獨立的文檔,而後再進行 match 查詢:
> db.blog.aggregate({"$unwind":"$comments"})
{
"results":
{
"_id":ObjectId("5359f6f6ec7452081a7873d7"),
"title":"這是一篇博客",
"author":"xiaoming",
"comments":{
"author":"lisa",
"date":ISODate("2019-01-01T17:52:04.148Z"),
"text":"Nice post"
}
},
{
"_id":ObjectId("5359f6f6ec7452081a7873d7"),
"title":"這是一篇博客",
"author":"xiaoming",
"comments":{
"author":"tom",
"date":ISODate("2019-01-01T17:52:04.148Z"),
"text":"I agree"
}
}
}
> db.blog.aggregate([
{"$unwind":"$comments"},
{"$match":{"comments.author":"lisa"}}
])
複製代碼
索引一般可以極大的提升查詢的效率,若是沒有索引,MongoDB在讀取數據時必須掃描集合中的每一個文件並選取那些符合查詢條件的記錄。這種掃描全集合的查詢效率是很是低的,特別在處理大量的數據時,查詢能夠要花費幾十秒甚至幾分鐘,這對網站的性能是很是致命的。索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構。
建立索引的基本語法以下:
db.collection.createIndex(
{key1: option1, key2: option2}, #key爲要建立索引的字段,option爲建立索引的方式:1 爲升序,-1 爲降序,能夠對多個字段建立索引,稱爲複合索引
{
background: <boolean>, #可選,建索引過程會阻塞其它數據庫操做,background 設置爲 true 可指定之後臺方式建立索引,默認值爲 false
unique: <boolean> #可選,創建的索引是否惟一。指定爲true建立惟一索引。默認值爲false
name: <string> #可選,索引的名稱。若是未指定,MongoDB的經過鏈接索引的字段名和排序順序生成一個索引名稱
sparse: <boolean> #可選,對文檔中不存在的字段數據不啓用索引;這個參數須要特別注意,若是設置爲true的話,在索引字段中不會查詢出不包含對應字段的文檔。默認值爲 false
}
)
複製代碼
對學生成績表建立索引:
> db.my_col.createIndex({"score": 1}, {background: true}) #在後臺建立
> db.my_col.getIndexes() #查看集合索引
> db.my_col.totalIndexSize() #查看集合索引大小
> db.my_col.dropIndex("索引名稱") #刪除集合指定索引
> db.my_col.dropIndexes() #刪除集合全部索引
複製代碼
MongoDB有一款跨平臺的可視化工具Robo 3T,很是簡潔易用。
下載安裝地址:robomongo.org/download
下載安裝成功以後,點擊 file → connect,彈出如下小窗口,而後點擊create,新建配置:
填入正確的地址和端口,保存便可。
按照上述教程安裝以後,若是你連不上所配置的MongoDB,排除網絡緣由,多是由於DB服務配置的監聽地址是127.0.0.1,須要改爲0.0.0.0哦。
雙擊配置好的鏈接,便可進入交互界面,以下圖所示,左邊是數據庫和集合等信息,右邊是查詢結果。能夠在命令行輸入查詢命令而後點擊執行,進行過濾等操做。
還能夠直接右鍵對文檔進行查看、編輯等操做,很是方便。
MongoDB菜鳥教程:www.runoob.com/mongodb/mon…
MongoDB高級查詢:cw.hubwiz.com/card/c/543b…
MongoDB聚合:cw.hubwiz.com/card/c/5481…
MongoDB官方文檔:docs.mongodb.com/manual/intr…
Robo 3T 使用教程:www.cnblogs.com/tugenhua070…> MongoDB 是一種NoSQL 數據庫,本文主要介紹MongoDB裏面的一些基本概念和操做、以及可視化工具的安裝和使用。
關注【IVWEB社區】公衆號獲取每週最新文章,通往人生之巔!