天天看點

mongodb 去重_看完這篇文章徹底入門MongoDB

mongodb 去重_看完這篇文章徹底入門MongoDB

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’}   //計算平均值
   }
  }
)
           
mongodb 去重_看完這篇文章徹底入門MongoDB

· 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
mongodb 去重_看完這篇文章徹底入門MongoDB

$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”)
           
mongodb 去重_看完這篇文章徹底入門MongoDB

建立索引後

db.t255.ensureIndex({name:1})
           
mongodb 去重_看完這篇文章徹底入門MongoDB

第一個是mongodb預設以_id為索引,第二個是我們建立的索引

db.t255.find().explain(“executionStats”)
           

查詢速度是0毫秒,這說明建立索引前後差距是很大的

mongodb 去重_看完這篇文章徹底入門MongoDB

· 在預設情況下索引字段的值可以相同

· 建立唯一索引(索引的值是唯一的),這樣可以去重,也是建立爬蟲去重的思路之一

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})