CentOS7.5之MongoDB4.0安裝與CRUD基本操作
一 MongoDB簡介
- MongoDB 是一個基於分布式文件存儲的數據庫。由 C++ 語言編寫。旨在為 WEB 應用提供可擴展的高性能數據存儲解決方案。
- MongoDB 是一個介於關系數據庫和非關系數據庫之間的產品,是非關系數據庫當中功能最豐富,最像關系數據庫的。
- MongoDB中的記錄是一個文檔,它是由字段和值對組成的數據結構。MongoDB文檔類似於JSON對象。字段的值可以包括其他文檔,數組和文檔數組。
二 MongoDB下載安裝
2.1 下載地址:
https://www.mongodb.com/download-center?jmp=nav#community
- MongoDB的版本偶數版本為穩定版,奇數版本為開發版。
- MongoDB對於32位系統支持不佳,所以3.2版本以後沒有再對32位系統的支持。
2.2 下載安裝
下載完安裝包,並解壓 tgz(以下演示的是 64 位 Linux上的安裝) 。
curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.0.0.tgz # 下載 tar -zxvf mongodb-linux-x86_64-rhel70-4.0.0.tgz # 解壓 mv mongodb-linux-x86_64-rhel70-4.0.0 /usr/local/mongodb # 將解壓包拷貝到指定目錄
MongoDB 的可執行文件位於 bin 目錄下,所以可以將其添加到 PATH 路徑中:
export PATH=<mongodb-install-directory>/bin:$PATH
<mongodb-install-directory> 為你 MongoDB 的安裝路徑。如本文的 /usr/local/mongodb 。
2.3 bin目錄結構
bsondump: binary-json,二進制文件,選擇性導出bson文件
mongo: 客戶端
mongod: 服務端
mongodump: 整體導出數據庫(二進制)
mongoexport:導出易識別的json文檔
mongoimport:導入json文檔
mongorestore:數據庫整體導入
mongos: 路由器(分片)
2.4 創建數據庫目錄
MongoDB的數據存儲在data目錄的db目錄下,但是這個目錄在安裝過程不會自動創建,所以你需要手動創建data目錄,並在data目錄中創建db目錄。
以下實例中我們將data目錄創建於MongoDB安裝目錄下。
註意:/data/db 是 MongoDB 默認的啟動的數據庫路徑(--dbpath)。
[root@node21 mongodb]$ mkdir -p data
[root@node21 mongodb]$ mkdir -p log/mongodb.log
2.5 運行 MongoDB 服務
你可以再命令行中執行mongo安裝目錄中的bin目錄執行mongod命令來啟動mongdb服務。 註意:如果你的數據庫目錄不是/data/db,可以通過 --dbpath 來指定。
[root@node21 mongodb]$ ./bin/mongod --dbpath ./data/ --logpath ./log/mongodb.log --port 27017 --fork
參數解釋: dbpath 數據存儲目錄 logpath 日誌存儲文件 port 運行端口(默認27017) fork 後臺靜默運行
查看MongoDB運行進程
[root@node21 mongodb]# ps aux |grep mongod
2.6 後臺管理 Shell
如果你需要進入MongoDB後臺管理,你需要先打開mongodb裝目錄的下的bin目錄,然後執行mongo命令文件。MongoDB Shell是MongoDB自帶的交互式Javascript shell,用來對MongoDB進行操作和管理的交互式環境。當你進入mongoDB後臺後,它默認會鏈接到 test 文檔(數據庫): $ cd /usr/local/mongodb
[root@node21 mongodb]# ./bin/mongo MongoDB shell version v4.0.0 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 4.0.0 Welcome to the MongoDB shell.
...
2.7 基本概念解釋
MongoDB術語/概念 |
解釋/說明 |
database |
數據庫 |
collection |
數據庫表/集合 |
document |
數據記錄行/文檔 |
field |
數據字段/域 |
index |
索引 |
primary key |
主鍵,MongoDB自動將_id字段設置為主鍵 |
2.8 Shell help 幫助解釋
參數 |
說明 |
--help –h |
返回基本幫助和用法文本 |
--version |
返回MongoDB的版本 |
--config<文件名> -f<文件名> |
指定包含運行時配置的配置文件 |
--verbose -v |
增加發送到控制臺日誌的數量 |
--quiet |
減少發送到控制臺日誌的數量 |
--port<端口> |
指定mongod的端口,默認27017 |
--bind_ip<端口> |
指定id地址 |
--maxConns<編號> |
指定鏈接的最大數 |
--logpath<路徑> |
指定日誌文件的路徑 |
--auth |
啟用遠程主機的身份驗證 |
--dbpath<路徑> |
指定數據庫實例的路徑 |
--nohttpinterface |
禁用HTTP接口 |
--nojournal |
禁用日誌 |
--noprealloc |
禁止預分配數據文件 |
--repair |
在所有數據庫上運行修復程序 |
2.9 MongoDB 數據類型
下表為MongoDB中常用的幾種數據類型。
數據類型 | 描述 |
---|---|
String | 字符串。存儲數據常用的數據類型。在 MongoDB 中,UTF-8 編碼的字符串才是合法的。 |
Integer | 整型數值。用於存儲數值。根據你所采用的服務器,可分為 32 位或 64 位。 |
Boolean | 布爾值。用於存儲布爾值(真/假)。 |
Double | 雙精度浮點值。用於存儲浮點值。 |
Min/Max keys | 將一個值與 BSON(二進制的 JSON)元素的最低值和最高值相對比。 |
Array | 用於將數組或列表或多個值存儲為一個鍵。 |
Timestamp | 時間戳。記錄文檔修改或添加的具體時間。 |
Object | 用於內嵌文檔。 |
Null | 用於創建空值。 |
Symbol | 符號。該數據類型基本上等同於字符串類型,但不同的是,它一般用於采用特殊符號類型的語言。 |
Date | 日期時間。用 UNIX 時間格式來存儲當前日期或時間。你可以指定自己的日期時間:創建 Date 對象,傳入年月日信息。 |
Object ID | 對象 ID。用於創建文檔的 ID。 |
Binary Data | 二進制數據。用於存儲二進制數據。 |
Code | 代碼類型。用於在文檔中存儲 JavaScript 代碼。 |
Regular expression | 正則表達式類型。用於存儲正則表達式。 |
ObjectId 類似唯一主鍵,可以很快的去生成和排序,包含 12 bytes,含義是:
- 前 4 個字節表示創建 unix時間戳,格林尼治時間 UTC 時間,比北京時間早了 8 個小時
- 接下來的 3 個字節是機器標識碼
- 緊接的兩個字節由進程 id 組成 PID
- 最後三個字節是隨機數
MongoDB 中存儲的文檔必須有一個 _id 鍵。這個鍵的值可以是任何類型的,默認是個 ObjectId 對象
由於 ObjectId 中保存了創建的時間戳,所以你不需要為你的文檔保存時間戳字段,你可以通過 getTimestamp 函數來獲取文檔的創建時間:
> var newObject = ObjectId()
> newObject.getTimestamp()
ISODate("2018-07-05T07:21:10Z")
ObjectId 轉為字符串
> newObject.str
5a1919e63df83ce79df8b38f
三 Mongodb入門命令
3.1 基本查看命令
show dbs 查看當前的數據庫
use databaseName 選庫
show tables/collections 查看當前庫下的collection
3.2 庫和集合的操作
db 查看當前所處的數據庫,在mongodb中,庫是隱式創建,你可以use 一個不存在的庫, 然後在該庫下創建collection,即可創建庫
db.dropDatabase(); 刪除database,把當前所用的庫給刪除了, 即使裏面有數據也會刪除
db.createCollection(‘collectionName’), 創建collection,collection也是允許隱式創建的
db.collectionName.insert(document); 在集合(表)中插入具體數據的時候會自動創建
db.collectionName.drop() , 刪除collection
測試隱式創建:往不存在的students表中插入數據
> show dbs admin 0.000GB config 0.000GB local 0.000GB > use admin switched to db admin > db.students.insert({name:‘zhangsan‘,age:‘20‘}) WriteResult({ "nInserted" : 1 }) > show tables students
刪除當前庫裏的students表
> db. students. drop()
true
四 Mongodb基本增刪改查
4.1 增加數據
mongodb存儲的是文檔,文檔是json格式的對象,我們向數據庫存儲數據的時候可以使用insert方法,數據格式要以js對象格式進行存儲:
語法:db.collectionName.insert(document);
db.students.insert({name:‘zhangsan‘,age:‘20‘}) 向當前students表裏插入數據
我們可以以多種方法對文檔進行存儲:
4.1.2 增加單篇文檔
語法:db.collectionName.insert({title:"nice day"});
4.1.3 增加單個文檔,並且指定_id
語法:db.collectionName.insert({_id:8,age:78,name:"lisi"});
_id 是我們在插入數據的時候,mongodb自動給文檔添加的一個屬性,如果我們不需要系統分配_id ,可以在添加數據的時候手動設置,覆蓋原有_id ,雖然_id 的類型可以自由指定,但是在同一個集合當中必須唯一,如果插入重復的值,系統會拋出異常.
這個_id 的名稱是固定的,它可以是Mongodb支持的任何數據類型,默認是ObjectId,在關系型數據庫中,主鍵通常是數值型的,並且可以設置自增,而Mongodb的主鍵,原生不支持自增主鍵.
4.1.4 增加多個文檔
db.students.insert( [{time:‘friday‘,value:‘mongodb‘},{_id:1,gender:‘male‘,name:‘QQ‘}])
可以以數組的方式,一次性向集合插入多個數據; 同時應該註意的是,由於mongodb采用的是JavaScript Shell,所以我們可以根據js特性,將文檔作為值賦給變量然後進行操作:
j = {name : ‘isi‘};
t = {name : ‘wangwu’}; db.students.insert([j,t]);
4.1.5 save和insert的區別
save和insert都可以進行數據的插入和增加,但是也有一些異同:
對於已存在數據{ _id:1, "name":"n1" },再次進行插入操作時,insert({_id : 1, "name" :"n2"}) 會報主鍵重復的錯誤提示 save({ _id:1, " name ":"n2"}) 會把n1修改為n2。
相同點:若新增的數據中沒有主鍵時,會增加一條記錄。
不同點:主鍵沖突時:insert 會報錯,save會自增_i d 主鍵插入
4.2 查詢操作
4.2.1 find()
無條件的普通查詢方式很簡單,可以直接使用
db.collectionName.find();一次可以查出指定集合中的所有數據
for(var i = 1;1<5;i++) { db.students.save({x:i,y:i+1}) } db.students.find();
如果出現顯示不全的現象,可以使用"it"命令,繼續顯示下面的數據. 當然,我們還可以按照條件進行查詢操作
語法: db.collection.find(查詢表達式,查詢的列);
例1: db.students.find({},{gendre:1})
查詢所有文檔,的gender屬性 (_id屬性默認總是查出來)
例2: db.students.find({},{gender:1, _id:0})
查詢所有文檔的gender屬性,且不查詢_id屬性
此處的0表示的是false,不查詢
例3: db.students.find({gender:’male’},{name:1,_id:0});
查詢所有gender屬性值為male的文檔中的name屬性
4.2.2 findOne()
findOne()和find()函數一樣,只是findOne()返回的是查詢結果中的第一條數據,或者返回null.
4.3 刪除操作
語法: db.collectionName.remove(查詢表達式, 選項);
選項是指 {justOne:true/false},是否只刪一行, 默認為false 註意
1: 查詢表達式依然是個json對象
2: 查詢表達式匹配的行,將被刪掉.
3: 如果查詢表達式為空對象{},collections中的所有文檔將被刪掉.
例1: db.students.remove({sn:‘001‘});
刪除stu表中sn屬性值為‘001‘的文檔
例2: db.students.remove({gender:‘m‘},true);
刪除stu表中gender屬性為m的文檔,只刪除1行.
4.4 修改操作
語法: db.collection.update(查詢表達式,新值,選項);
*改哪幾行? --- 查詢表達式 *改成什麽樣? -- 新值 或 賦值表達式 *操作選項 ----- 可選參數 upsert:如果要更新的那條記錄沒有找到,是否插入一條新紀錄,默認為false
multi :是否更新滿足條件的多條的記錄,默認為false
multi :是否更新滿足條件的多條的記錄,false:只更新第一條,true:更新多條,默認為false
例:db.news.update({name:‘QQ‘},{name:‘MSN‘});
是指選中news表中,name值為QQ的文檔,並把其文檔值改為{name:"MSN"},
結果: 文檔中的其他列也不見了,改後只有_id和name列了.即是新文檔直接覆蓋了舊文檔,而不是修改.
4.4.1 修改操作中的關鍵字
如果是想修改文檔的某列,可以用$set關鍵字
例:db.collectionName.update(query,{$set:{name:’QQ’}})
修改時的賦值表達式
- $set 修改某列的值
- $unset 刪除某個列
- $inc 增長某個列
- $rename 重新命名某列
- $setOnInsert 當upsert為true時,並且發生了insert操作時,可以補充的字段.
$inc實例
按照指定的步長增長某個列;
> db.students.insert({"uid":"201203","type":"1",size:10}) > db.students.find() { "_id" : ObjectId("5003b6135af21ff428dafbe6"), "uid" : "201203", "type" : "1", "size" : 10 } > db.students.update({"uid" : "201203"},{"$inc":{"size" : 2}}) > db.stdentsu.find() { "_id" : ObjectId("5003b6135af21ff428dafbe6"), "uid" : "201203", "type" : "1", "size" : 12 }
$unset實例
>db.students.find({_id:3}) {"_id" : 3 , "age" : 18} > db.students.update({_id:3},{$unset:{age:‘sss‘}}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 }) > db.students.update({_id:3},{$unset:{age:‘sss‘}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.students.find({_id:3}) { "_id" : 3 }
$rename實例
->db.students.insert({name:‘lisi‘,age:12,sex:‘male‘,height:123,area:‘haidian‘}); ->db.students.update({name:‘lisi‘},{$set:{area:‘chaoyang‘},$unset:{height:1},$inc:{age:1},$rename:{sex:‘gender‘}});
4.4.2 Option選項的作用
語法: {upsert:true/false,multi:true/false}
upsert:是指沒有匹配的行,則直接插入該行
例:db.stu.update({name:‘wuyong‘},{$set:{name:‘junshiwuyong‘}},{upsert:true});
如果有name=‘wuyong‘的文檔,將被修改,如果沒有,將添加此新文檔
例:db.news.update({_id:99},{x:123,y:234},{upsert:true});
沒有_id=99的文檔被修改,因此直接插入該文檔
multi: 是指修改多行(即使查詢表達式命中多行,默認也只改1行,如果想改多行,可以用此選項)
例:db.news.update({age:21},{$set:{age:22}},{multi:true});
則把news中所有age=21的文檔,都修改
4.5 查詢表達式
我們無論在修改刪除還是查詢的過程中,都需要傳入查詢表達式對目標數據進行查詢,表達式有很多種
1: 最簡單的查詢表達式 {filed:value} ,是指查詢field列的值為value的文檔 2: $ne:!= {field:{$ne:value}} db.stu.find({age:{$ne:16}}) 作用--查age列的值 不等於16的文檔 3:$gt:大於 $lt:小於 $gte:大於或等於 $lte:小於或等於 4: $in:[] 查詢某列的值在範圍內的文檔 db.goods.find({cat_id:{$in:[2,8]}} 5: $nin:not in 查詢某列不在範圍內的文檔 $nin:[2,3,5] 6: $exists 語法: {field:{$exists:1}} 作用: 查詢出含有field字段的文檔 7:用正則表達式查詢 以”諾基亞”開頭的商品 例:db.goods.find({goods_name:/諾基亞.*/},{goods_name:1});
五 遊標操作
通俗的說,遊標不是查詢結果,而是查詢的返回資源,或者接口,通過這個接口,你可以逐條對數據進行讀取;
聲明遊標:
var cursor = db.collectioName.find(query,projection);
cursor.hasNext() //判斷遊標是否已經取到盡頭
cursor.next() //取出遊標的下1個單元
用while來循環遊標
> var mycursor = db.bar.find({_id:{$lte:5}}) > while(mycursor.hasNext()) { printjson(mycursor.next());}
遊標還有一個叠代函數,允許我們自定義回調函數來逐個處理每個單元.
cursor.forEach(回調函數); > var gettitle = function(obj) {print(obj.goods_name)} > var cursor = db.goods.find(); > cursor.forEach(gettitle);
遊標在分頁中的應用
比如查到10000行,跳過100頁,取10行,一般地,我們假設每頁N行, 當前是page頁,就需要跳過前 (page-1)*N 行, 再取N行.
在mongo中,分頁是用skip(), limit()函數來實現的
//查詢結果中,跳過前9995行 var mycursor = db.bar.find().skip(9995); //查詢第901頁,每頁10條 則是 var mytcursor = db.bar.find().skip(9000).limit(10);
六 group分組
mongodb支持聚合運算;
在goods表中插入數據
db.goods.insert([ {‘_id‘:3,‘cat_id‘:6,‘price‘:29}, {‘_id‘:4,‘cat_id‘:7,‘price‘:30}, {‘_id‘:5,‘cat_id‘:6,‘price‘:31}, {‘_id‘:6,‘cat_id‘:7,‘price‘:32}, {‘_id‘:7,‘cat_id‘:7,‘price‘:28}, ])
如果我們所處的是mysql數據庫,我們可以這樣查詢每個類下面的商品平均價格
select avg(price) from goods group by cat_id;
但如果在mongodb下,我們如何查詢分組內的平均值呢? 我們需要使用mongodb的聚合運算 https://docs.mongodb.com/manual/aggregation/
db.goods.aggregate([ {$match:{}}, {$group:{_id:"$cat_id",avg:{$avg:‘$price‘}}} ]);
其中,$match表示匹配的條件,$group表示分組的條件,$avg表示求平均值. 當然,指令還有很多,我們還可以使用limit,sort等操作
db.goods.aggregate([ {$match:{}}, {$group:{_id:"$cat_id",avg:{$avg:‘$price‘}}}, {$limit:1} ]); db.goods.aggregate([ {$match:{}}, {$sort:{price:-1}} ]);
七 MapReduce
7.1 MapReduce原理
隨著大數據興起,MapReduce的概念也越來越火,通常的概念是用於大規模數據集(1TB)的並行運算,實際上就是傳統關系型數據庫的group概念的延伸.
MapReduce之所以能夠流行,是因為數據的大,當數據過大的時候,單個服務器無法承載,facebook,微軟等等的數據中心都是分布在世界各地的,我們所需 要的數據很可能分布在不同的服務器甚至世界各地.在這時候,我們就無法使用group操作了.
MapReduce通俗的講,最大的優點就是可以支持分布式的group
而MapReduce的操作即分為map和reduce兩步;
map ---> 映 射
reduce ---> 減少,規約,回歸
7.2 MapReduce統計價格
//按照cat_id 分配 price,把price數據映射到一個數組上 var map = function(){ emit(this.cat_id , this.price) } //將映射好的數組進行操作 var reduce = function(cat_id,number){ return Array.avg(number) } //將統計的數據映射到res表當中db.goods.mapReduce(map,reduce,{out:‘res‘})
接下來我們使用mapReduce功能實現地震數據的統計
7.3 下載並導入地震信息
在國家地震科學數據共享中心下載過去一年的地震數據 http://data.earthquake.cn/sjfw/index.html?PAGEID=datasourcelist&dt=40280d0453e414e40153e44861dd0003
將數據保存為csv格式,導入到mongodb數據庫中,使用mongoimport
-d : 指明導入文件存放在哪個數據庫
-c : 指明導入文件存放在哪個集合
--type:指明要導入的文件格式。
--headerline:指明不導入第一行,csv格式的文件第一行為列名。
--file:指明要導入的文件路徑。
./bin/mongoimport -d test -c dz --type csv --file /usr/local/src/dz.csv --headerline
7.4 按照經緯度統計數據
我們規約的時候按照經緯度的5*5方格進行分組,如果在此方格內存在地震,則地震+1
var map = function(){ var jd = parseInt(this.jd/5)*5; var wd = parseInt(this.wd/5)*5; var area = jd + ‘:‘ + wd; emit(area,1);//如果該區域有地震,則統計為1 } var reduce = function(area,nums){ return Array.sum(nums); } db.dz.mapReduce(map,reduce,{out:‘dzrs‘});
成功獲取區間範圍內的地震次數,此時我們要將數據導出為json,做成熱力圖;
7.5 熱力圖
使用百度地圖開放平臺的熱力圖api http://lbsyun.baidu.com/index.php?title=jspopular
填入密鑰,生成熱力圖
7.6 展示地震數據
轉化地震數據為規定的json格式
var course = db.dzrs.find();
var row;
course.forEach(function(obj){ row = obj._id.split(‘:‘);
db.reli.insert({lng:parseInt(row[1])+2.5,lat:parseInt(row[0])+2.5,count:obj.value}) })
導出json
./bin/mongoexport -d test -c reli -o /usr/local/src/reli.json
將json數據放入熱力圖當中並配置熱力圖相關選項.
CentOS7.5之MongoDB4.0安裝與CRUD基本操作