1. 程式人生 > >CentOS7.5之MongoDB4.0安裝與CRUD基本操作

CentOS7.5之MongoDB4.0安裝與CRUD基本操作

agg 測試 布爾 分配 unity 基本上 page 原理 utc

一 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基本操作