
1、mongodb基本指令
1、檢視目前資料庫:db
2:檢視所有資料庫:show dbs / show databases
3、切換資料庫: use +資料庫名字
4、删除目前的資料庫:db.dropDatabase()
2、集合(collection)的基本指令
1、展示特定資料庫中所有集合:show collections
2、删除集合:db . 集合名 . drop()
3、向不存在的集合(collection)中第一次加入資料時,集合會被建立出來
4、手動建立集合db.createCollection(name,options)
如: db.createCollection(‘sub’,{capped:true,size:10})
參數capped:預設值為false,表示無上限,值為ture時表示設定上限
參數size:當capped值為true時,需要制定此參數,表示上限大小,當文檔達到上限時候,講會覆寫之前的資料,機關為位元組。
3、資料類型
1、ObjectID:文檔ID
2、String:字元串
3、Boolean:布爾值
4、Integer:整數
5、Double:存儲浮點值
6、Arrays:數組或者清單,多個值存儲到一個鍵
7、Object:用于嵌入式的文檔,即一個值一個文檔
8、Null:存儲Null值
9、Timestamp:時間戳,表示從1970-1-1到現在的總秒數
10、Date:存儲目前日期或者時間的UNIX時間格式
注意:· 每個文檔都有一個屬性為:_id,保證每個文檔的唯一性,
· 可以自己去設定_id插入文檔,如果沒有提供,那麼MongoDB為每個文檔提供一個獨特的_id,類型為objectID
· objectID是一個12位元組的十六進制數:
前4個位元組為目前的時間戳
接下來3個位元組為機器ID
接下來2個位元組為MongoDB的服務程序id
最後3個位元組是簡單的增量值
4、基本操作
1、插入資料 save和insert的差別
db.collection.insert({}) 插入的資料,如果_id已經存在,則報錯
db.collection.save({}) 插入的資料,如果_id已經存在,則會更新
2、簡單查詢 db.collection名.find()
3、更新 db.集合名稱.update(<query>,<update>,{multi:<boolean>})
參數:query:查詢條件
參數update: 更新操作符,更新成什麼
參數multi:可選,預設是false,表示隻更新找到的第一條記錄,值為true表示把滿足條件的文檔全部更新
例子:
db.collection.update({name:’xiaoming’},{name:’xiaohua’ })
結果是:資料中除了_id,
隻剩下了name字段,其他的字段沒有了
db.collection.update({name:’xiaoming’},{$set:{name:’xiaohua’} })
結果是:資料中隻更新了name字段,其他的字段正常顯示
db.collection.update({},{$set:{name:’xiaohua’} },{multi:true}) 更新全部
4、删除 db.集合名稱.remove(<query>,{
justOne:<boolean>})
參數query:可選,删除的文檔的條件
參數justOne:可選,如果設為true或者1,則隻删除一條,預設為false,表示删除多條(預設删除滿足所有條件的記錄)
5、進階查詢
1、find() :查詢所有
2、findOne() : 查詢,隻傳回第一個 db.集合名稱.findOne({})
3、pretty() :将結果格式化 db.集合名稱.findOne({}).pretty()
6、運算符
1、比較運算符
· 等于:預設就是等于,沒有運算符
· 小于:$lt
· 小于等于: $lte
· 大于: $gt
· 大于等于 : $gte
· 不等于 : $ne
例子: db.集合名稱.find({ age:{ $gte: 18 } })
2、範圍運算符
$in,$nin 判斷是否在某個範圍内
如:查詢年齡為18,28,38的學生
db.集合名稱.find( { age: { $in[18,28,38] } } )
3、邏輯運算符
and: 同時滿足條件
db.集合名稱.find( { age:18,name:’xiaoming ’} )
or:使用
$or例子:查詢年齡大于18,或者姓名為false的學生
db.集合名稱.find( { $or:[{age:{$gt:18}} , { gender:false }] } )
4、mongodb支援正規表達式
例子:查找sku屬性以adb開頭
db.products.find({sku:/^abc/})
例子:查找sku屬性以789結尾
db.products.find({sku:{/$regex:’789$’/}})
7、進階操作
1、limit 和 skip
limit() : 用于讀取指定數量的文檔
db.stu.find().limit(2)
skip() : 用于跳過指定數量的文檔
db.stu.find.skip(2)
同時使用
db.stu.find.skip(5).limit(4)
2、自定義查詢 $where
使用$where後面寫一個函數,傳回滿足條件的資料
查詢年齡大于30的學生
db.stu.find( {
$where : function () {
return this.age>30; //this 指定是每一條
}
} )
3、投影
在查詢到的傳回結果中,隻選擇必要的字段
db.集合名稱.find({ } , { 字段名稱:1,... })
參數為字段與值,值為1表示顯示,值為0則不顯
特殊:對于_id 列預設是顯示的,如果不顯示需要明确設定為0
db.stu.find({ } , { _id:0,name:1 } )
4、排序
sort() :用于對集進行排序
db.集合名稱.find().sort( { 字段1:1,... } )
參數1:升序排列, -1為降序排列
5、統計個數
count() : 統計結果集的文檔條數
兩種書寫方式
①:db.collection.find( {條件} ).count()
②:db.collection.count({條件})
6、消除重複
distinct() : 對資料進行去重
db.集合名稱.distinct(‘去重字段’,{條件})
例子:db.stu.distinct(‘hometown’, { age: {$gt: 18}})
注意:當sort,skip,limit一起使用時,無論其位置變化,總是先sort再skip,最後limit
8、資料的備份和恢複
備份的文法(cmd指令)
mongodump -h dbhost -d dbname -o dbdirectory
-h : 伺服器位址,也可以指定端口号
-d : 需要備份的資料庫名稱
-o : 備份的資料存放位置,此目錄中存放着備份出來的資料
例子: mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1bak
資料恢複
恢複文法:
mongorestore -h dbhost -d dbname -dir dbdirectory
-h : 伺服器位址,也可以指定端口号
-d : 需要恢複的資料庫執行個體
-dir : 備份資料所在位置
9、聚合指令(難點)
聚合(aggregate)是基于資料處理的聚合管道,每個文檔通過一個由多個階段(stage)組成的管道,可以對每個階段的管道進行分組,過濾等功能,然後經過一系列的處理,輸出相應的結果。
db.集合名稱.aggregate( { 管道: { 表達式 } } )
常用管道:
$group:講集合中的文檔分組,可用于統計結果
$match : 過濾資料,隻輸出符合條件的文檔,類似于find()
$project : 修改輸入文檔的結構,如重命名、增加、删除字段、建立計算結果
$sort : 講輸入文檔排序後輸出
$limit : 限制聚合管道傳回的文檔數
$skip : 跳過指定數量的文檔,并傳回餘下的文檔
$unwind : 将數組類型的字段進行拆分
mongodb表達式
文法: 表達式 : ‘$列名’
$sum : 計算綜總和,$sum:1 表示以一倍計數
$avg : 計算平均值
$min:計算最小值
$max :計算最大值
$push : 在結果文檔中插入值到一個數組中
$first : 根據資源文檔的排序擷取第一個文檔資料
$last: 根據資源文檔的排序擷取最後一個文檔資料
$group
· 将集合中的文檔分組,可用于統計結果
· _id 表示分組的依據(也就是依照哪個字段進行分組),使用某個字段的格式為 ‘$ 字段’
例1:統計男生、女生的總人數,按照gender分組,并計算每組平均年齡
db.stu.aggregate(
{ $group :
{
_id: ‘$gender’,
count:{ $ sum :1}, //計算總數,1:表示每一行計數1,這樣總數就是每一組的總條數
avg_age:{ $avg: ‘$age’} //計算平均值
}
}
)
· group by null 将集合中所有的文檔分為一組
例2:求學生總人數和平均年齡
db.stu.aggregate(
{$group :{
_id:null,
count:{$sum :1},
avg_age:{ $avg: ‘$age’}
}}
)
$project
輸出的結果中如果不想顯示_id的話,就要用到 $project
在這裡加一個管道,$group輸出的結果
db.stu.aggregate(
{$group :{ _id:’$gender’,count:{$sum :1},avg_age:{ $avg: ‘$age’}}},
{$project:{ gender:’$_id’,count:’$count’,avg_age:’$ave_age’}}
)
如果不想顯示_id , 就寫入
_id:0, 正常顯示的字段就寫入
count:1$match
· 用于過濾資料,隻輸出符合條件的文檔
· 使用MongoDB的标準查詢操作
· 與find的差別:
match是管道指令,能将結果交給後一個管道,但是find不可以例1:查詢年齡大于20的學生
db.stu.aggregate(
{$match : {age:{$gt : 20} }}
)
例2:選擇年齡大于20的學生,觀察男性和女性有多少人
db.stu.aggregate(
{$match : {age:{$gt:20}}},
{$group:{ _id:’$gender’,count:{$sum : 1} }},
{$project:{ gender:’$_id’, count:1 , _id:0}}
)
例3:小練習
{“country”: “china”,”province”:”sh”,”userid”:”a”}
{“country”: “china”,”province”:”sh”,”userid”:”b”}
{“country”: “china”,”province”:”sh”,”userid”:”a”}
{“country”: “uk”,”province”:”sh”,”userid”:”c”}
{“country”: “china”,”province”:”bj”,”userid”:”da”}
{“country”: “china”,”province”:”bj”,”userid”:”fa”}
要求:統計出每個country/province下的userid的數量(同一個userid隻統計一次)
db.stu.aggregate(
//去重,通過将country、province和userid三個屬性同時進行分類,那麼一樣的就會分到一組,然後輸出,就達到了去重的作用
{$group:{ _id:{ country:”$country”,province:”$province”,userid:”$userid” } }},
{$group:{ _id:{ country:”$country”,province:”$province”}, count:{ $sum:1} }},
{$project:{_id:0,country:”$_id.country”,province:”$_id.province”, count:1 }}
)
$sort
· 将輸入文檔排序後輸出
例1:查詢學生資訊,按照年齡升序
db.stu.aggregate(
{ $sort: { age:1 }}
)
例2:查詢男生、女生人數、按照人數降序
db.stu.aggregate(
{$group:{ _id:”$gender”,count:{$sum:1} }}
{$sort:{ count:-1 }}
)
$limit和$skip
· $limit : 限制聚合管道傳回的文檔數
例1:查詢2條學生資訊
db.stu.aggregate({ $limit:2 })
· $skip : 跳過指定數量的文檔,并傳回餘下的文檔
例子2:查詢從第3條開始的學生資訊
db.stu.aggregate({ $skip:2 })
例3:統計男生、女生人數、按照人數升序、取第二條資料
db.stu.aggregate(
{ $group:{ _id:”$gender”,count:{ $sum:1 } } },
{ $sort:{count:1 } },
{ $skip:1 },
{$limit:1},
)
注意:先寫skip,在寫limit $unwind
· 将文檔中的某一個數組類型字段拆分成多條,每條包含數組中的一個值
文法:db.集合名稱.aggregate( {$unwind: “$字段名稱” } )
例1:
db.stu.insert({ _id:1,item:’t-shirt’, size:[ ‘S’,’M’,’L’ ] })
db.stu.aggregate( {$unwind:’$size’} )
輸出結果
{ _id:1,item:’t-shirt’, size:‘S’ }
{ _id:1,item:’t-shirt’, size:‘M’ }
{ _id:1,item:’t-shirt’, size:‘L’ }
練習:資料庫找那個有一條資料:{“username”:”Alex”,”tags”:[“C++”,”Js”,”Java”]},如何擷取tags清單的長度?
思路:
①:聚合查詢,通過$match查找到這條資料
②:$unwind将tags拆分
③:$group擷取資料的總條數
db.stu.aggragate(
{$match:{ username:”Alex” }},
{$unwind:”$tags”},
{$group:{ _id:null, count:{$sum:1} } }
)
$unwind的注意事項
如果資料庫中有以下資料
{“_id”:1,“item”:”a”,”size”:[“S”,”M”,”L”]}
{“_id”:2,“item”:”b”,”size”:[ ]}
{“_id”:3,“item”:”c”,”size”:”M”}
{“_id”:4,“item”:”d”}
{“_id”:5,“item”:”e”,”size”:null}
運作:db.stu.aggregate({ $unwind:’$size’ })
結果
{“_id”:1“item”:”a”,”size”:”S”}
{“_id”:1,“item”:”a”,”size”:”M”}
{“_id”:1,“item”:”a”,”size”:”L”}
{“_id”:3,“item”:”c”,”size”:”M”}
而其他三條資料并沒有傳回,被删除了,那我們如何讓它們正常傳回呢?
就需要另一個參數:
preserveNullAndEmptyArrays,當為true時,表示保留屬性為空的文檔
用法:
db.stu.aggregate(
{$unwind:{
path:’$字段名稱’,
preserveNullAndEmptyArrays:<boolean> //防止資料丢失
}}
)
10、建立索引
1、索引:提升查詢速度
文法:db.集合.ensureIndex( { 屬性:1 } ), 1表示升序,-1表示降序
具體操作:db.t255.ensureIndex({name:1})
1或者-1,基本沒什麼差别,隻有當需要排序的時候才有差別,比如,當降序的時候-1比較快,反之,1比較快
mongodb通過
explain(“executionStats”)來檢測查詢的速度,輸出結果中的屬性
executionTimeMillis值是查詢所需要的的時間,機關為毫秒
測試:插入10萬條資料到資料庫中
for(i=0;i<100000;i++){db.t255.insert({name:’test’+i,age:i})}
建立索引之前
db.t255.find().explain(“executionStats”)
建立索引後
db.t255.ensureIndex({name:1})
第一個是mongodb預設以_id為索引,第二個是我們建立的索引
db.t255.find().explain(“executionStats”)
查詢速度是0毫秒,這說明建立索引前後差距是很大的
· 在預設情況下索引字段的值可以相同
· 建立唯一索引(索引的值是唯一的),這樣可以去重,也是建立爬蟲去重的思路之一
db.t1.ensureIndex({name:1},
{“unique”:true})
簡單講一下爬蟲資料去重,實作增量式爬蟲
· 使用資料庫建立關鍵字段(一個或者多個)建立索引進行去重
思路一: 根據url位址進行去重
① url位址對應的資料不會變的情況,url位址能夠唯一判别一條資料的情況
② 首先,将url存到redis中,拿到url之後,判斷url在redis的url集合中是否存在,
如果存在,說明該url已經請求過了,不再請求,如果不存在,說明該url沒被請求過,
把url存入redis的集合中
③ 這方面有一個很厲害的算法:布隆過濾器
思路二:根據資料本身進行去重
①選擇特定的字段,使用加密算法(md5,sha1)将字段進行加密,生成字元串,
存入redis的集合中
②後續新來一條資料,同樣的方法進行加密,如果得到的字元串在redis中存在,
說明資料存在,對資料進行更新,否則說明資料不存在,直接插入
· 通過多個字段來判斷資料的唯一性的時候可以建立聯合索引
db.t1.ensureIndex({name:1},{age:1})
· 檢視目前集合所有索引
db.t1.getIndexes()
· 删除索引
db.t1.dropIndex({‘索引名稱’: 1})