mongoDB 是由C++語言編寫的,是一種分佈式的面向文檔存儲的開源nosql數據庫。nosql是Not Only SQL的縮寫,是對不一樣於傳統的關係型數據庫的數據庫管理系統的統稱。javascript
mongoDB是無模式的文檔數據庫,在關係型數據庫中,數據表的每一行都擁有同樣的字段,字段的名字和數據類型在建立table的時候就基本肯定了,如student表的每一行都有學生編號、學生姓名、年齡等字段;而在mongoDB中,存儲數據的格式相似於Json(格式爲Bson),每個document的字段的名字和數據類型能夠徹底不一樣,如在一個collection下,第一個document能夠存儲學生信息(學生編號、姓名、年齡、性別等),第二個document能夠存儲班級信息(班級編號,班級名等)。正是由於無模式的特色,讓咱們能夠無需多餘操做就能完成數據的橫向擴展。下表是mongoDB和傳統數據庫術語的對應關係。java
SQL術語 | MongoDB | 解釋/說明 |
---|---|---|
database | database | 數據庫 |
table | collection | 數據庫表/集合 |
row | document | 數據記錄行/文檔 |
column | field | 數據字段/域 |
index | index | 索引 |
join | $lookup | 錶鏈接 |
primary key | primary key | 主鍵,MongoDB自動將_id字段設置爲主鍵 |
mongoDB的安裝步驟十分簡單,下載地址:https://www.mongodb.com/download-center#community。若是咱們想在Windows上安裝mongoDB直接下載msi文件,雙擊安裝便可。若是要將mongoDB安裝在Linux系統上,步驟以下:linux
####第1步 下載解壓mongdb #下載解壓二進制包,解壓即安裝 cd /usr/local/src/ curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.9.tgz tar -zxvf mongodb-linux-x86_64-4.0.9.tgz mv mongodb-linux-x86_64-4.0.9 /usr/local/mongodb ####第2步 添加配置文件 vim /usr/local/mongodb/bin/mongodb.conf 配置文件內容以下: systemLog: destination: file logAppend: true path: /usr/local/mongodb/logs/mongodb.log storage: dbPath: /usr/local/mongodb/data journal: enabled: true processManagement: fork: true net: port: 27017 bindIp: 0.0.0.0 #配置文件中指定的dbpath和log要本身添加,否則會報錯,執行命令 mkdir -p /usr/local/mongodb/data; mkdir -p /usr/local/mongodb/logs/;cd /usr/local/mongodb/logs/; touch mongodb.log ####第3步 加載配置文件運行 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/bin/mongodb.conf ####第4步 添加環境變量,用於能夠在任意目錄下執行mongo命令 vim ~/.bash_profile #修改當前用戶下的環境變量 PATH=$PATH:$HOME/bin:/usr/local/mongodb/bin source ~/.bash_profile
安裝完成後,在任意目錄下使用命令 mongo 192.168.70.133:27017 (mongo命令會默認啓動127.0.0.1:27017)啓動mongodb,mongoDB使用的是javascript shell,咱們簡單測試一下,若是出現下邊的界面表示安裝成功了sql
這裏簡單使用一下mongoDB的shell來添加、刪除數據庫和collection:mongodb
mongoDB的GUI有MongoDB Compass、studio 3T等,這裏使用的是Robomongo,下載地址:https://robomongo.org/,下載完成後一直Next安裝便可,鏈接mongoDB效果以下,Robomongo是傻瓜式的用法,能夠經過客戶端添加collection,document,執行shell等,具體使用方法就再也不詳細介紹了。shell
· 數據庫
咱們也能夠經過shell腳本鏈接數據庫,在Robomongo執行shell命令以下:json
//鏈接遠程數據庫 var mongo=new Mongo("192.168.70.133:27017") //找到數據庫 var db=mongo.getDB("myDB"); //找到collecttion var collection=db.getCollection("userinfo"); //查詢colletion中全部數據 var list=collection.find().toArray(); //json形式打印結果 printjson(list);
咱們已經知道mongoDB是面向文檔的nosql數據庫,由於其無模式的特色,形成它的操做要比關係型數據庫複雜一些,這裏簡單介紹一下mongoDB的CRUD操做。注意:從3.2版本開始,mongoDB添加了一些xxxOne()和xxxMany()方法,咱們儘可能使用這些新的方法。vim
添加數據的指令是insert,使用方法以下:數組
insert方法的參數也能夠是數組,用於批量添加數據,以下:
db.userinfos.insert([ {_id:1, name: "張三", age: 23}, {_id:2, name: "李四", age: 24} ]);
從3.2版本,mongoDB添加了insertOne和insertMany方法,分別用於單條插入和批量插入,用法很簡單,以下:
//insertOne用於單條添加 db.userinfos.insertOne( {_id:1, name: "張三", age: 23} ); //insertMany用於批量添加 db.userinfos.insertMany([ {_id:1, name: "張三", age: 23}, {_id:2, name: "李四", age: 24} ]);
mongoDB查詢使用find函數,語法以下:
mongoDB使用find查詢時,默認會返回主鍵_id,若是不想返回主鍵的話設置_id=0便可。mongoDB的查詢語法是比較簡單的,可是由於其無模式的特色,且field的值能夠是對象和數組,形成mongoDB的運算符要比傳統的關係型數據庫多不少,如運算符$exists可用於查詢field是否存在、$type用於判斷filed的類型等等,這裏彙總了一些經常使用的查詢相關的運算符,有興趣的小夥伴能夠測試一下:
測試數據: db.userinfos.insertMany([ {_id:1, name: "張三", age: 23,level:10, ename: { firstname: "san", lastname: "zhang"}, roles: ["vip","gen" ]}, {_id:2, name: "李四", age: 24,level:20, ename: { firstname: "si", lastname: "li"}, roles:[ "vip" ]}, {_id:3, name: "王五", age: 25,level:30, ename: { firstname: "wu", lastname: "wang"}, roles: ["gen","vip" ]}, {_id:4, name: "趙六", age: 26,level:40, ename: { firstname: "liu", lastname: "zhao"}, roles: ["gen"] }, {_id:5, name: "田七", age: 27, ename: { firstname: "qi", lastname: "tian"}, address:'北京' }, {_id:6, name: "周八", age: 28,roles:["gen"], address:'上海' } ]); |
||||
類別 | 運算符 | 說明 | 實例 | 執行結果 |
比較運算符 |
$gt($gte) | 大於(大於等於) | db.userinfos.find( ) |
查找age>25的文檔的name 結果: [{ "_id" : 4, "name" : "趙六" }, { "_id" : 5, "name" : "田七" }] |
$lt($lte) | 小於(小於等於) | db.userinfos.find( { age:{$lt:25}}, ) |
查找age<25的文檔的name 結果: [ { "_id" : 1, "name" : "張三" }, { "_id" : 2, "name" : "李四" } ] |
|
$eq | 等於 | db.userinfos.find( { age:{$eq:25}}, ) |
查詢age=25的文檔的name 結果: [ { "_id" : 3, "name" : "王五" } ] |
|
$ne | 不等於 | db.userinfos.find( |
查詢age!=25的文檔的name 結果: [{"_id" : 1,"name" : "張三"}, |
|
$in | 包含 | db.userinfos.find( { age:{$in:[24,25]}}, |
查詢age在[24,25]中的文檔的name 結果: [ { "_id" : 2, "name" : "李四" }, { "_id" : 3, "name" : "王五" } ] |
|
$nin | 不包含 | db.userinfos.find( { age:{$nin:[24,25]}}, |
查詢age不在[24,25]中的文檔的name 結果: [{"_id" : 1,"name" : "張三"}, |
|
邏輯運算符 | $and | 與 | db.userinfos.find( {$and: [ {name:{$eq:'張三'}}, {age:{$eq:23}} ]}, {name:1} )
|
查詢name='張三'且age=23的文檔 結果: [ { "_id" : 1, "name" : "張三" } ] |
$not | 非 |
db.userinfos.find( {age:{$not:{$in:[23,24,25]}}}, |
查詢age不在[23,24,24]中的文檔 結果: [ { "_id" : 4, "name" : "趙六" }, { "_id" : 5, "name" : "田七" } ] |
|
$or | 或
|
db.userinfos.find( {$or: [ {name:{$eq:'張三'}}, {age:{$eq:24}} ]}, {name:1} ) |
查詢name='張三'或者age=24的文檔 結果: [ { "_id" : 1, "name" : "張三" }, { "_id" : 2, "name" : "李四" } ] |
|
$nor | 或的取反 |
db.userinfos.find( {$nor: [ {name:{$eq:'張三'}}, {age:{$eq:24}} ]}, {name:1} ) |
上邊栗子的取反操做 結果: [ {"_id" : 3,"name" : "王五"}, |
|
評估運算符 | $mod | 取餘 | db.userinfos.find( {age:{$mod:[10,3]}}, |
查詢name%10=3的文檔 結果: [ { "_id" : 1, "name" : "張三" } ] |
$regex | 正則 | db.userinfos.find( {name:{$regex:/^張/i}}, |
查詢name以張開頭的文檔 結果: [ { "_id" : 1, "name" : "張三" } ] |
|
db.userinfos.find( {name:{$in:[/^張/,/四$/]}}, |
查詢name以張開頭或者以四結尾的文檔 結果: [ { "_id" : 1, "name" : "張三" }, { "_id" : 2, "name" : "李四" } ] |
|||
$where | where過濾 | db.userinfos.find( ) |
查詢名字爲張三的記錄 結果: [ { "_id" : 1, "name" : "張三" } ] 注意:where能夠實現全部的過濾,可是效率不高。 這是由於where採用逐行判斷而不使用索引 |
|
$expr | 表達式過濾 | db.userinfos.find( ) |
查詢age<level的記錄 結果: [ { "_id" : 3, "name" : "王五" }, { "_id" : 4, "name" : "趙六" } ]
|
|
元素運算符 | $exists | field是否存在 | db.userinfos.find( ) |
查詢存在address字段的文檔 結果: [ { "_id" : 5, "name" : "田七" }, { "_id" : 6, "name" : "周八" } ] |
$type | field類型 | db.userinfos.find( {name:{$type:'string'}}, {name:1} ) |
查詢name爲string的文檔 結果: 全部文檔都匹配 |
|
數組運算符 | $all | 包含全部元素才匹配成功 | db.userinfos.find( {roles:{$all:['vip','gen']}}, {name:1} ) |
查詢roles中包含vip和gen的文檔 結果: [ { "_id" : 1, "name" : "張三" }, { "_id" : 3, "name" : "王五" } ] |
$eleMatch | 只要有一個元素符合就匹配成功 | db.userinfos.find( {roles:{$elemMatch:{ $eq: 'vip', $ne: 'gen' }}}, {name:1} ) |
查詢roles中有元素等於vip,或有元素不等於gen的文檔 結果: [{"_id" : 1,"name" : "張三"}, |
|
$size | 元素個數相同的匹配成功 | db.userinfos.find( {roles:{$size:2}}, {name:1} ) |
查詢roles中有兩個元素的文檔 結果: [ { "_id" : 1, "name" : "張三" }, { "_id" : 3, "name" : "王五" } ] |
mongoDB修改documen使用的命令是update,語法以下:
mongoDB的update默認只修改一條document,若是想修改全部符合條件的documet的話,能夠設置multi:true。upsert表示當沒有符合過濾條件的文檔時,就添加一條文檔,並將修改的內容做爲新增document的值。mongoDB的update功能比較豐富,如能夠修改field的名字,刪除field,以及對數組進行增刪改。從3.2版本開始,mongoDB添加了updateOne()和updateMany()方法,用於修改單條或者多條數據,推薦使用新的方法,語法以下:
//將age<25的記錄的level修改成50,只修改一條。updateOne至關於update設置multi:false db.userinfos.updateOne( {age:{$lt:25}}, {$set:{level:50}} ) //將age<25的記錄的level修改成50,全部符合條件的記錄都修改。updateMany至關於update設置multi:true db.userinfos.updateMany( {age:{$lt:25}}, {$set:{level:50}} )
這裏彙總了mongoDB中關於update的相關運算符,有興趣的小夥伴能夠測試一下:
測試數據: db.userinfos.insertMany([ {_id:1, name: "張三", age: 23,level:10, ename: { firstname: "san", lastname: "zhang"}, roles: ["vip","gen" ]}, {_id:2, name: "李四", age: 24,level:20, ename: { firstname: "si", lastname: "li"}, roles:[ "vip" ]}, {_id:3, name: "王五", age: 25,level:30, ename: { firstname: "wu", lastname: "wang"}, roles: ["gen","vip" ]}, {_id:4, name: "趙六", age: 26,level:40, ename: { firstname: "liu", lastname: "zhao"}, roles: ["gen"] }, {_id:5, name: "田七", age: 27, ename: { firstname: "qi", lastname: "tian"}, address:'北京' }, {_id:6, name: "周八", age: 28,roles:["gen"], address:'上海' } ]); |
||||
值操做運算符 | $currentDate | 修改field值爲當前時間, 若是field不存在則添加field |
db.userinfos.update( createtime:{$type:'timestamp'}} } |
將張三的createtime字段值修改成當前時間 格式爲時間戳("createtime" : Timestamp(1560663270, 1)) 補充:若是不設置$type,默認的格式爲date 格式爲date("createtime" : ISODate("2019-06-16T05:38:21.119Z"))
|
$set | 修改值 |
db.userinfos.update( {level:20} } |
將張三的level修改成20。若是要修改的field不存在,不會添加新的field。 | |
$setOnInsert | 只有在新增document時進行賦值, 必定要設置upsert:true |
db.userinfos.update( {level:30} }, |
由於已經有name=張三的document,因此不作任何操做 | |
db.userinfos.update( |
添加一個name=吳九的document,並設置level爲30 | |||
$inc | 自增 | db.userinfos.update( {age:10} } |
張三的age自增10,age修改成23+10=33 | |
$mul | 自乘 | db.userinfos.update( {age:2} } |
張三的age自乘2,age修改成23*2=46 | |
$min | 取小 | db.userinfos.update( {age:13} } |
張三的age取小值,由於23>13,因此修改age爲13。若是修改的值比23大,那麼不作操做。 | |
$max | 取大 | db.userinfos.update( {age:33} } |
張三的age取大值,由於23<33,因此修改age爲33。若是修改的值比23小,那麼不作操做。 | |
字段操做運算符 | $rename | 修改filed的名字 | db.userinfos.update( {name:'張三'}, {age:'年齡'} } |
將張三的age字段名改爲年齡,值不變,年齡=23 |
$unset | 刪除field | db.userinfos.update( {name:'張三'}, {level:''} } |
將張三的level字段刪除 |
測試數據: db.students.insertMany( [{ "_id" : 1, "grades" : [ 85, 80, 80 ] }, { "_id" : 2, "grades" : [ 88, 90, 92 ] }] ) |
||||
數組運算符 | $ | 單個佔位符 | db.students.updateOne( |
修改_id=1的文檔graders中第一個值爲80的元素,值改爲82 結果: [{ "_id" : 1, "grades" : [ 85, 82, 80 ] }, |
$[] | 全部元素佔位符 | db.students.updateOne( |
修改_id=1的文檔graders中全部元素,值改爲100 結果: [{ "_id" : 1, "grades" : [ 100, 100, 100 ] }, |
|
$[<identifier>] | 符合arrayFilter過濾條件的元素佔位符 | db.students.updateOne( |
修改_id=2的文檔graders中大於等於90的元素,值改爲100 結果: [{ "_id" : 1, "grades" : [ 85, 82, 80 ] }, |
|
$push | 添加元素 | db.students.updateOne( |
在_id=1的文檔graders中添加元素 結果: [{ "_id" : 1, "grades" : [ 85, 80, 80 ,98 ] }, |
|
$addToSet | 添加不存在的元素,若是元素已經存在則無操做 | db.students.updateOne( { _id: 1 }, { $addToSet: { "grades" : 100 } } ) |
在_id=1的文檔graders中添加元素 結果: [{ "_id" : 1, "grades" : [ 85, 80, 80 ,98,100 ] }, 補充:若是添加的元素是85,由於85已經存在,因此不執行操做 |
|
$pop | 彈出(移除)元素 | db.students.updateOne( |
移除最後一個元素 結果: [{ "_id" : 1, "grades" : [ 85, 80 ] }, 補充:若是{ $pop: { "grades" : -1 } }表示從前邊彈出,移除第一個元素 |
|
$pullAll | 根據值移除數組中的元素 | db.students.update( |
移除_id=2的文檔的graders中值爲88,90的全部元素 結果: [{ "_id" : 1, "grades" : [ 85, 80, 80 ] }, |
|
$pull | 移除符合條件的元素 | db.students.update( |
移除_id=2的文檔的graders中大於90的全部元素 結果: [{ "_id" : 1, "grades" : [ 85, 80, 80 ] }, |
|
數組批量添加 相關運算符 |
$each | 和$push,$addToSet配合使用,用於批量添加元素 | db.students.update( {grades:{$each:[99,100]}} } ) |
在_id=1的文檔graders中添加元素[99,100] 結果: [{ "_id" : 1, "grades" : [ 85, 80, 80 ,99,100 ] }, |
$slice | 和$push,$each配合使用,用於限制元素個數 | db.students.update( {grades:{$each:[99,100],$slice:4}} } |
在_id=1的文檔graders中添加元素[99,100] 結果: [{ "_id" : 1, "grades" : [ 85, 80, 80 ,99] }, 若是使用$slice:-4,則保留後4個元素 |
|
$sort | 和$push,$each配合使用,在添加元素後進行排序 | db.students.update( {grades:{$each:[70,100],$sort:1}} } |
在_id=1的文檔graders中添加元素[99,100],並排序 結果: [{ "_id" : 1, "grades" : [70,80,80,85,100]}, 若是使用$sort:-1,則倒序排序 |
|
$position | 和$push,$each配合使用,指定插入元素的位置 | db.students.update( {grades:{$each:[70,100],$position:1}} } |
在_id=1的文檔graders中,從索引1開始插入元素[99,100] 結果: [{ "_id" : 1, "grades" : [85,70,100,80,80]}, |
在3.2之前的版本中,mongoDB使用remove方法來刪除文檔,用法以下:
從3.2版本開始,提供了deleteOne()和deleteMany()方法,分別用於刪除單條和多條document,語法以下:
//刪除單條document,功能相似於remove設置justOne:true db.userinfos.deleteOne({age:{$gt:25}}) //刪除全部符合條件的document,功能相似於remove設置justOne:false db.userinfos.deleteMany({age:{$gt:25}})
本篇是mongoDB的第一篇,簡單介紹了mongoDB的安裝方法,經過js shell進行mongoDB的CRUD操做,後續會逐步介紹mongoDB的索引、數據聚合、GridFS和C#驅動,以及副本集和sharing集羣搭建。若是本文由錯誤的地方,但願你們能夠指出,我會及時修改,謝謝。