MongoDB

關于database的基礎命令

? 查看當前的數據庫:db
? 查看所有的數據庫:show dbs / show databases
? 切換數據庫:use db_name
? 刪除當前數據庫:db.dropDatabase()

mongodb不需要創(chuàng)建數據庫,無論有沒有數據庫,當我們使用use命令時都可以直接切換,存入數據時,才會自動創(chuàng)建。

關于集合(類表)的基礎命令

不手動創(chuàng)建集合
向不存在的集合中第一次加入數據時,集合被創(chuàng)建出來。

手動創(chuàng)建集合

  db.createCollection(name,options)
  db.createCollection("stu")
  db.createCollection("sub",{capped:true,size:10})

參數capped:默認值為false表示不設置上限,值為true表示設置上限
參數size:當capped值為true時,需要指定此參數,表示上限大小,當文檔達到上限時,會將之前的數據覆蓋,單位為字節(jié)。

查看集合

show collections

刪除集合

db.collection_name.drop()

數據類型

  • Object ID:文檔ID
  • String:字符串,最常用的,必須是有效的UTF-8
  • Boolean:存儲一個布爾值,true或false
  • Integer:整數可以是32位或64位,這取決于服務器
  • Double:存儲浮點值
  • Arrays:數組或列表,多個值存儲到一個鍵
  • Object:用于嵌入式的文檔,即一個值為一個文檔(就是一個字典)
  • Null:存儲Null值
  • Timestamp:時間戳,表示從1970-1-1到現在的總秒數
  • Date:存儲當前日期或時間的UNIX時間格式

注意:

  • 創(chuàng)建日期語句如下:參數的格式為YYYY-MM-DD
    new Date('2017-12-20')
  • 每個文檔都有一個屬性,為_id, 保證每個文檔的唯一性
  • 可以自己去設置_id插入文檔,如果沒有提供,那么MonogoDB為每一個文檔提供了獨特的_id,類型為objectID
  • objectID是一個12字節(jié)的十六進制數:
    • 前4個字節(jié)為當前時間戳
    • 接下來3個字節(jié)為機器ID
    • 接下來的2個字節(jié)中MongoDB的服務進程ID
    • 最后3個字節(jié)是簡單的增量值

插入

 db.db_name.insert(document)
 db.db_name.insert({name:"bruce",age:18})
 db.db_name.insert({_id:"20181204",name:"bruce",gender:1})
  • 插入文檔時,如果不指定_id參數,MongoDB會為文檔分配一個唯一的ObjectID
  • 如果執(zhí)行insert操作,_id重復的話,會拋出錯誤。

保存

 db.collection_name.save(document)
  • 如果文旦的_id已經存在則修改,如果文檔的_id不存在則添加
  • save執(zhí)行時,_id重復的話,會執(zhí)行更新操作。

簡單查詢

db.db_name.find()
db.collection_name.find()

更新

db.collection_name.update(<query>,<update>, {multi:<boolean>})
  • 參數query:查詢條件
  • 參數update:更新操作符
  • 參數multi:可選,默認是false,表示只更新找到的第一條記錄,
  • 值為true表示把模擬組條件的文檔全部更新
db.collection_name.update({name:'br'},{name:'hr'}) //更新一條(替換)
db.collection_name.update({name:'br'},{$set:{name:'hr'}}) //更新一條(更新)
db.collection_name.update({},{$set:{gender:0}},{multi:true}) //更新全部

注意:multi update only works with $ operators

刪除

db.collection_name.remove(<query>,{justOne:<boolean>})
  • 參數query:可選,刪除的文檔的條件
  • 參數justOne:可選,如果設為true或1,則只刪除一條,默認false,表示刪除多條

數據查詢

  • 方法find():查詢
  db.collection_name.find({條件文檔})

例:db.collection_name.find({age:20})

  • 方法findOne():查詢,只返回第一個
  db.collection_name.findOne({條件文檔})
  • 方法pretty():將結果格式化
  db.集合名稱.find({條件文檔}).pretty()

比較運算符

  • 等于:默認是等于判斷,沒有運算符
    -小于:$lt (less than)
  • 小于等于:$lte(less than equal)
  • 大于:$gt (greater than)
    -大于等于:$gte
  • 不等于:$ne
    例:db.collection_name.find({age:{$gte:18}})

范圍運算符

使用$in, $nin 判斷是否在某個范圍呢
查詢年齡為18、28的學生

db.collection_name.find({age:{$in:[18,28,38]}})

邏輯運算符

  • and 在json中寫多個條件即可
db.collection_name.find({name:"br",age:18})

例:查詢年齡大于或等于18,并且性別為true的學生

db.collection_name.find({age:{$gte:18},gender:true})
  • or 使用$or , 值為數組,數組中每個元素為json

例:查詢年齡大于18,或性別為false的學生

db.collection_name.find({$or:[{age:{$gt:18}},{gender:false}]})

例: 查詢年齡大于18或性別為男生,并且姓名是郭靖

db.collection_name.find({$or:[{age:{$gt:18}},{gender:true}],name:"郭靖"})

支持正則表達式

使用//或$regex編寫正則表達式

db.collection_name.find({name:/^abc/})
db.collection_name.find({name:{$regex:"123$"}})

limit 和skip

  • 方法limit():用于讀取指定數量的文檔
  db.collection_name.find().limit(NUMBER)

查詢兩條學生信息

db.collection_name.find().limit(2)
  • 方法skip():用于跳過指定數量的文檔
db.collection_name.find().skip(NUMBER)
db.collection_name.find().skip(2)
  • 同時使用
    可以實現分頁, 后者效率低一些
db.collection_name.find().limit(4).skip(5) 
db.collection_name.skip(5).limit(4) 

自定義查詢

使用$where后面寫一個函數,返回滿足條件的數據
查詢年齡大于30的學生

db.collection_name.find({
    $where:function(){
        return this.age>30;
    }
})

我們平時寫的都是json格式的命令參數,其實MongoDB可以直接接收js命令的。

投影

在查詢到的返回結果中,只選擇必要的字段

db.collection_name.find({},{字段名稱:1,...})

參數為字段與值,值為1表示顯示,值為0不顯示
特殊:對于_id列默認是顯示的,如果不顯示需要明確設置為0,除了_id字段之外的其他字段,如果不顯示,不能寫為0.否則會報錯。

db.collection_name.find({},{_id:0,name:1,gender:1})

排序

方法sort(),用于對集合進行排序

db.collection_name.find().sort({字段:1,...})

參數1為升序排序
參數-1為降序排序
根據性別降序,再根據年齡升序

db.collection_name.find().sort({gender:-1,age:1})

統(tǒng)計個數

方法count()用于統(tǒng)計結果集中文檔條數

db.collection_name.find({條件}).count()
db.collection_name.count({條件})

例:

db.collection_name.find({gender:false}).count()
db.collection_name.count({age:{$gt:20},gender:true})

find和count的條件不能同時使用。(不確定,待測試)

消除重復

方法distinct()對數據進行去重

db.collection_name.distinct('去重字段',{條件})
db.collection_name.distinct('hometown',{age:{$gt:18}})

數據的備份和恢復

備份的語法:

mongodump -h dbhost -d dbname -o dbdirectory

-h : 服務器地址,也可以指定端口號(本機可以省略)
-d : 需要備份的數據庫名稱
-o : 備份的數據存放的位置,此目錄中存放著備份出來的數據

mongodump -h localhost:27017 -d test - o ~/testbak

該命令不是在MongoDB的客戶端執(zhí)行的,是在我們操作系統(tǒng)的終端執(zhí)行的

恢復語法:

mongorestore -h dbhost -d dbname --dir dbdirectory

-h : 服務器地址(本機可以省略)
-d : 需要恢復的數據庫實例
--dir : 備份數據所在位置

mongorestore -h localhost:27017 -d test1 --dir ~/testbak

聚合 aggregate

聚合(aggregate)是基于數據處理的聚合管道,每個文檔通過一個由多個階段(stage)組成的管道,可以對每個階段的管道進行分組、過濾等功能,然后經過一些列的處理,輸出相應的結果。

db.collection_name.aggregate({管道:{表達式}})

例:

db.collection_name.aggregate([
    {$match:{status:"A"}},  # stage
    {$group:{_id:"$cust_id",total:{$sum:"$amount"}}}  # stage
])

管道

在mongodb中,文檔處理完畢后,通過管道進行下一次處理。常用管道如下幾種。

$group:將集合中的文檔分組,可用于統(tǒng)計結果

  1. 將集合中的文檔分組,可用于統(tǒng)計結果
  2. _id表示分組的依據,使用某個字段的格式為’$字段’
  3. 例1:按照性別進行分組,獲取不同組數據的個數和平均年齡
db.collection_name.aggregate(
      {$group:{
               _id:’$gender’,
               counter:{$sum:1},
               avg_age:{$avg:”$age”}
        }}
)

例2:按照hometown進行分組,獲取不同組的平均年齡

db.collection_name.aggregate(
      {$group:{
            _id:”$hometown”,
            avg_age:{$avg:”$age”}
      }}
)
  1. group by null
    將集合中所有文檔分為一組
    例3:求學生總人數、平均年齡(使用$group統(tǒng)計整個文檔)
db.collection_name.aggregate(
      {$group:{
            _id:null,
            count:{$sum:1},
            avg_age:{$avg:”$age”}
      }}
)

注意:

  1. $group對應的字典中有幾個鍵,結果中就有幾個鍵
  2. 分組依據需要放到_id后面
  3. 取不同的字段的值需要使用,gender,$age
  4. 取字段嵌套的字典中的值得時候$_id.country
  5. 能夠同時按照多個鍵進行分組group:{_id:{country:"_id.country",province:"_id.province"},count:{sum:1}}

$match:過濾數據,主輸出符合條件的文檔

  1. 用于過濾數據,只輸出符合條件的文檔, 功能等同于find。
  2. match是管道命令,能將結果交給后一個管道,但是find不可以。
  3. 使用MongoDB的標準查詢操作
  4. 例1:查詢年齡大于20的學生
db.collection_name.aggragate(
  {$match:{age:{$gt:20}}}
)

例2:查詢年齡大于20的男生、女生人數

db.collection_name.aggragate(
{$match:{age:{$gt:20}}},
{$group:{_id:”$gender”,counter:{$sum:1}}}
)

例3:

db.collection_name.aggragate(
{$match:{$or:[{age:{$gt:20}},{hometown:{$in[“大理”,”麗江”]}}]}},
{$group:{_id:”$gender”,counter:{$sum:1}}},
{$project:{_id:0,gender:”$_id”,counter:1}}
)

$project:修改輸入文檔的結構,如重命名、增加、刪除字段、創(chuàng)建計算結果

  1. 修改輸入文檔的結構,如重命名、增加、刪除字段、創(chuàng)建計算結果
  2. 例1查詢學生的姓名、年齡
db.collection_name.aggregate(
    {$project:{_id:0,name:1,age:1}}
)

例2:查詢男生、女生人數,輸出人數

db.collection_name.aggragate(
      {$group:{_id:”$gender”,counter:{$sum:1}}},
      {$project:_id:0,counter:1}
)

例3:

db.collection_name.aggregate(
      {$group:{
            _id:’$gender’,
            counter:{$sum:1},
            avg_age:{$avg:”$age”}
      }},
      {$project:{
            gender:”$_id”,
            count:”$count”,
            avg_age:”$avg_age”,
            _id:0
      }}
)

練習:統(tǒng)計出每個country/province下的userid的數量(同一個userid只統(tǒng)計一次)

{"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"}
db.collection_name.aggregate({
    $group:{_id:{country:"$country",province:"$province",userid:"$userid"}},
    $group:{_id:{country:"$_id.country",province:"$_id.province"},count:{$sum:1}},
    $project:{country:"$_id.country",province:"$_id.province",count:1,_id:0}
})

$sort:將輸入文檔排序后輸出

  1. 將輸入文檔排序后輸出
  2. 例1:查詢學生信息,按年齡排序
db.collection_name.aggregate({
    $sort:{age:1}
})

例2:查詢男生、女生人數,按人數降序

db.collection_name.aggregate({
    $group:{_id:"$gender",counter:{$sum:1}}},
    {$sort:{counter:-1}
})

$limit:限制聚合管道返回的文檔數

  1. 限制聚合管道返回的文檔數
  2. 例1:查詢2條學生信息
db.collection_name.aggregate($limit:2)

$skip:跳過指定數量的文檔,并返回余下的文檔

  1. 跳過指定數量的文檔,并返回余下的文檔
  2. 例1:查詢從第三條開始的學生信息
db.collection_name.aggregate($skip:2)

例2:查詢從第三條開始的兩條數據

db.collection_name.aggregate({$skip:2},{$limit:2})

例3:統(tǒng)計男生、女生人數,按人數升序,取第二條數據

db.collection_name.aggregate(
    {$group:{_id:"$gender",counter:{$sum:1}}},
    {$sort:{counter:1}},
    {$skip:1},
    {$limit:1}
)

$unwind:將數組類型的字段進行拆分

  1. 將文檔中的某一個數組類型字段拆分成多條,每條包含數組中的一個值。
  2. 語法:db.collection_name.aggregate({unwind:”字段名稱”})
db.collection_name.insert({_id:1,item:"t-shirt",size:["S","M","L"]})
db.collection_name.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#’,’java’,’c++’]},如何獲取該tag列表的長度?

db.collection_name.aggregate(
    {$match:{username:"Alex"}}
    {$unwind:"$tags"},
    {$group:{_id:null,sum:{$sum:1}}}
)

屬性值為false表示丟棄屬性值為空的文檔
屬性preserveNullAndEmptyArrays值為true表示保留屬性值為空的文檔
用法:

db.collection_name.aggregate({
    $unwind:{
        path:'$字段名稱',
        preserveNullAndEmptyArrays:<boolean> # 防止數據丟失
    }
})

例:

db.collection_name.insert(
    {_id:1,item:"a",size:["S","M","L"]},
    {_id:2,item:"b",size:[ ]},
    {_id:3,item:"bc",size:["S"]},
    {_id:4,item:"d"},
    {_id:5,item:"e",size:null}
)
db.collection_name.aggregate({$unwind:"$size"})
db.collection_name.aggregate({
    $unwind:{
        path:"$size",
        preserveNullAndEmptyArrays:true
    }
})

表達式

處理輸入文檔并輸出
語法:表達式:"$列名"

常用表達式:
$sum:就算總和,$sum:1 表示以一倍計數
$avg:計算平均值
$min:獲取最小值
$max:獲取最大值
$push:在結果文檔中插入值到一個數組中
$first:根據資源文檔的排序獲取第一個文檔數據
$last:根據資源文檔的排序獲取最后一個文檔數據

索引創(chuàng)建

索引:以提升查詢速度
測試:插入10萬條數據到數據庫中

for(i=0;i<100000;i++){db.collection_name.insert({name:'test'+i, age:i})}
db.collection_name.find({name:'test10000'})
db.collection_name.find({name:'test10000'}).explain('executionStats')

建立索引之后對比:
語法:db.collection_name.ensureIndex({屬性:1}),1表示升序,-1表示降序
具體操作:

db.collection_name.ensureIndex({name:1})
db.collection_name.find({name:'test10000'}).explain('executionStats'

索引操作

  1. 在默認情況下索引字段的值可以相同
  2. 創(chuàng)建唯一索引(索引的值是唯一的)
db.collection_name.ensureIndex({'name':1},{"unique":true})
  1. 建立聯合索引(什么時候需要聯合索引)
    多個字段確定一條數據的唯一性
db.collection_name.ensureIndex({name:1,age:1})
  1. 查看當前集合的所有索引
db.collection_name.getIndexes()
  1. 刪除索引
db.collection_name.dropIndex("索引名稱")

MongoDB MySQL Redis的區(qū)別和使用場景

  1. MySQL是關系型數據庫,支持事務
  2. MongoDB,Redis非關系型數據庫,不支持事務
  3. MySQL MongoDB Redis的實用根據如何方便進行選擇
    a) 希望速度快的時候選擇MongoDB或者是Redis
    b) 數據量過大的時候,選擇頻繁使用的數據存入redis,其他的存入MongoDB
    c) MongoDB不用提前建表建數據庫,使用方便,字段數據不確定的時候使用MongoDB
    d) 后續(xù)需要用到數據之間的關系,此時考慮MySQL

爬蟲數據去重,實現增量式爬蟲
使用數據庫建立關鍵字字段(一個或者多個)的唯一索引進行去重。
根據URL地址進行去重。

  1. 使用場景
    URL地址對應的數據不會變得情況,URL地址能夠唯一判別一條數據的情況
  2. 思路
    URL存在Redis中,拿到URL地址,判斷URL在Redis中的URL的集合中是否存在,存在,說明URL已經被請求國,不再請求,不存在,URL地址沒有被請求國,請求,把該URL存入Redis集合中
  3. 布隆過濾器
    使用多個加密算法加密URL地址,得到多個值
    往對應值的位置把結果設置為1
    新來一個URL地址,一樣通過加密算法生成多個值
    如果對應位置的值全為1,說明這個URL地址已經抓過
    否則沒有抓過,就把對應位置的值設置為1
    根據數據本身進行去重
  4. 選擇特定的字段,使用加密算法(md5,sha1)將字段進行加密,生成字符串,存入redis集合中
  5. 后續(xù)新來一條數據,同樣的方法進行加密,如果得到的字符串在Redis中存在,說明數據存在,對數據進行更新,否則說明數據不存在,直接插入。

動手
嘗試將我電腦中的douban.tv1中的數據恢復到自己的電腦中,具體如何操作?
完成上述操作后完成以下問題:

  1. 獲取每條數據中的title,count(所有評分人數),rate(評分),country(國家的這些字段)
db.collection_name.aggregate(
    {$project:{title:1,_id:0,count:"$rating.count",rate:"$tating.value",country:"$tv_category"}}
)
  1. 獲取上述結果中的不同國家電影的數據量
db.collection_name.aggregate(
    {$project:{title:1,_id:0,count:"$rating.count",rate:"$tating.value",country:"$tv_category"}},
    {$group:{_id:"country",count:{$sum:1}}}
)
  1. 獲取上述結果中分數大于8分的不同國家電視劇的數據量
db.collection_name.aggregate(
    {$project:{title:1,_id:0,count:"$rating.count",rate:"$tating.value",country:"$tv_category"}},
    ${match:{rate:{$gt:8}}},
    {$group:{_id:"country",count:{$sum:1}}},
    {$project:{_id:0,country:"$_id",count:1}}
)

實例化和插入、更新

from pymongo import MongoClient

class TestMongo:
    def __init__(self):
        # 實例化client 建立連接
        client = MongoClient(host='127.0.0.1', port=27017)
        # client[數據庫][集合]
        self.collection = client["test"]["t1"]  # 使用方括號的方式選擇數據庫和集合

    # 插入一條數據
    def test_insert(self):
        # insert接收字典,返回objectId
        ret = self.collection.insert({name:"test1000",age:33})
        print(ret)

    # 插入多條數據
    def test_insert_many(self):
        item_list = [{name:"test1000{}".format(i)} for i in range(10)]
        # insert_many接收一個列表,列表中為所有需要插入的字典
        t = self.collection.insert_many(item_list)
        # t.inserted_ids為所有插入的id
        for i in t.inserted_ids:
            print(i)

    def try_find_one(self):
        # find_one查找并且返回一個結果,接收一個字典形式的條件
        t = self.collection.find_one({name:"test1000"})
        print(t)

    def try_find(self):
        # 查詢所有
        t = collection.find()
        for i in t:
            print(i)

    def try_find_many(self):
        # find返回所有滿足條件的結果,如果條件為空,則返回數據庫的所有
        t = self.collection.find({name:"test1111"})
        # 結果是一個cursor游標對象,是一個可迭代對象,可以類似讀文件的指針
        for i in t:
            print(i)
        for i in t: #此時t中沒有內容
            print(i)

    def try_update_one(self):
        # update_one更新一條數據
        self.collection.update_one({name:"test2"},{$set:{name:new_test11}})

    def try_update_many(self):
        # update_many更新全部數據
        self.collection.update_many({name:"test111"},{$set:{name:"new_test222"}})

    def try_delete_one(self):
        # delete_one刪除一條數據
        self.collection.delete_one({name:"test10010"})

    def try_delete_many(self):
        # delete_many刪除所有滿足條件的數據
        self.collection.delete_many({name:"test10010"})

練習:

  1. 使用Python想集合t3中插入1000條文檔,文檔的屬性包括_id、name
    a) _id的值為0、1、2、3……999
    b) Name的值為py0、py1……
data_list = [ {"_id":i,"name":"py{}".format(i)} for i in range(1000) ]
collection.insert_many(data_list)
  1. 查詢顯示出_id為100的整倍數的文檔,如100、200、300……, 并將name輸出
ret = collection.find()
data_list = list(ret)
data_list = [i for i in data_list if i["_id"]%100==0 and i["_id"]!=0]
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Mongodb的特點: 模式自由:可以把不同結構的文檔存儲在同一個數據庫里 面向集合的儲存:適合儲存JSON風格文...
    姓高名旭升閱讀 816評論 0 0
  • 簡介 MongoDB 是一個基于分布式文件存儲的NoSQL數據庫 由C++語言編寫,運行穩(wěn)定,性能高 旨在為 WE...
    大熊_7d48閱讀 37,862評論 1 9
  • 首先安裝好 MongoDB 數據庫并啟動它,然后進入用 CMD 命令進入到 ${MONGODB_HOME}/bin...
    本宮在丶爾等都是妃閱讀 483評論 0 2
  • 安裝 MongoDB Windowns、Ubuntu17.10 下安裝 MongoDB教程在此 MongoDB 幫...
    Kangvcar閱讀 2,183評論 0 13
  • Mongodb的特點: 模式自由:可以把不同結構的文檔存儲在同一個數據庫里 面向集合的儲存:適合儲存JSON風格文...
    浮_屠閱讀 2,881評論 0 0

友情鏈接更多精彩內容