MongoDB數據庫的使用

MongoDB是一個基於分佈式 文件存儲的NoSQL數據庫,適合存儲JSON風格文件的形式。python

  • 三元素:數據庫、集合和文檔。

    • 文檔:對應着關係數據庫中的行,就是一個對象,由鍵值對構成,是json的擴展Bson形式,示例
      {'name':'guojing','gender':''}
    • 集合:相似於關係數據庫中的表,儲存多個文檔,結構不固定,示例
      {'name':'guojing','gender':''}
      {'name':'huangrong','age':18}
      {'book':'shuihuzhuan','heros':'108'}

1、環境安裝與運行

  • 安裝

    sudo apt-get install mongodb

  配置文件爲 /etc/mongodb.conf,默認端口號:27017正則表達式

  • 啓動服務器

    sudo service mongodb start  #至關於執行命令 sudo mongod --config /etc/mongod.conf
  • 關閉服務器

    sudo service mongodb stop
  • 重啓服務器

    sudo service mongodb restart #修改了配置文件/etc/mongodb.conf後,須要重啓mongodb服務器讓配置生效
  • 啓動客戶端

    sudo mongo

2、數據庫操做

  • 查看當前數據庫

    db
  • 查看全部數據庫

    show dbs
  • 切換(或建立)數據庫

    use 數據庫名

    切換數據庫,若是數據庫不存在,當插入數據或建立集合時,會自動建立這個數據庫sql

  • 刪除數據庫

    db.dropDatabase()

    刪除當前指向的數據庫,若是不存在,則什麼也不作mongodb

3、集合操做

  • 建立

    db.createCollection(name[,options])
    #name集合名稱
    #options可選,是一個用於指定集合配置的文檔,其中capped參數默認不設置上限(false),若設置上限(true)則須要指定參數size,單位字節
    #不設置集合大小
    db.createCollection("stu")
    #設置集合大小
    db.createCollection("sub", { capped : true, size : 10 } )
  • 查看當前數據庫集合

    show collections
  • 刪除集合

    db.集合名.drop()

4、數據操做

  • 插入

    db.集合名.insert(文檔) 或 db.集合名.insert([文檔...])
    #若是不指定_id字段,則分配一個惟一的ObjectId;若是指定_id字段,且_id已經存在時,不作任何操做;若是一次性插入多條數據,以數組的方式傳入文檔
    # 不指定_id
    db.stu.insert({name:'gj',gender:1})
    
    #指定_id
    s1={_id:'20160101',name:'hr'}
    s1.gender=0
    db.stu.insert(s1)
  • 刪除--(注意justOne參數)

    db.集合名.remove(條件,{justone:<boolean>}) #參數justOne默認false,刪除多條
    # 只刪除匹配到的一條數據
    db.stu.remove({gender:0},{justOne:true})
    
    #刪除全部
    db.stu.remove({})
  • 修改--(注意$set以及multi參數)

    db.集合名.update({條件},$操做符,{multi: <boolean>}]) #參數multi只和$操做符一塊兒使用,默認false,只修改一條數據,true表示修改多條數據
    # 不使用操做符$set,修改整條文檔
    db.stu.update({name:'hr'},{name:'mnc'})
    
    #使用操做符$set指定屬性修改
    db.stu.update({name:'hr'},{$set:{name:'hys'}})
    
    #multi參數和$set一塊兒使用,修改多條文檔
    db.stu.update({},{$set:{gender:0}},{multi:true})
  • 保存

    db.集合名.save(document) 
    #在手動插入_id字段時,若是_id已經存在,作全文檔更新操做,其他均表示插入數據。
    db.stu.save({_id:'20160102','name':'yk',gender:1})
    db.stu.save({_id:'20160102','name':'wyk'}) #對上述文檔作修改
  • 查詢

    • 基本查詢

      db.集合名.find({條件文檔}) #查詢全部
      db.集合名.findOne({條件文檔}) #只查詢第一條
      db.集合名.find({條件文檔}).pretty() #結果格式化輸出
    • 比較運算符

      • 等於:默認,沒有運算符
      • 小於: $lt
      • 小於等於: $lte
      • 大於:$gt
      • 大於等於:$gte
      • 不等於:$ne
        #查詢年齡大於等於18的學生
        db.stu.find({"age":{$gte:18}})
    • 邏輯運算符

      • 邏輯與:默認
      • 邏輯或:$or
        # 查詢年齡大於或等於18,而且性別爲1的學生
        db.stu.find({"age":{$gte:18},"gender":1})
        
        #查詢年齡大於18,或性別爲0的學生
        db.stu.find({$or:[{"age":{$gt:18}},{"gender":1}]})
        
        #查詢年齡小於18或者大於20,性別爲1的學生
        db.stu.find({$or:[{"age":{$lt:18}},{"age":{$gt:20}}],"gender":1})
    • 範圍運算符

      • 在某個範圍$in,後面接數組
      • 不在某個範圍$nin,後面接數組
        #查詢年齡1八、20以及22歲的學生
        db.stu.find({"age":{$in:[18,20,22]}})
        
        #查詢年齡不等於18或20的學生
        db.stu.find({"age":{$nin:[18,20]}})
    • 正則表達式

      • 使用/表達式/或者$regex
        #查詢姓黃的學生
        db.stu.find({"name":/^黃/})
        db.stu.find({"name":{$regex:"^黃"}})
    • 自定義查詢

      • 使用$where:function(){return 知足條件的數據表達式}------運算符使用js語法,好比邏輯與(&&),邏輯或(||)
        #查詢年齡18-22的學生
        db.stu.find({$where:function(){return this.age>18 && this.age<22}})
        
        #查詢年齡小於18或者大於22的學生
        db.stu.find({$where:function(){return this.age<18 || this.age>22}})
    • 投影

      • 只顯示部分字段
        db.集合名.find({條件},{字段名:1,...}) #1表示該字段顯示,0不顯示;_id列默認顯示,不顯示須要明確設置爲0
        #查詢姓名和年齡(顯示_id)
        db.stu.find({},{name:1,gender:1})
        
        #查詢姓名和年齡(不顯示_id)
        db.stu.find({},{_id:0,name:1,gender:1})
    • skip

      • 跳過指定數量的文檔
        db.集合名.find({條件}).skip(number) #number默認爲0
        #查詢從第3條開始的學生信息
        db.stu.find().skip(2)
    • limit

      • 讀取指定數量的文檔
        db.集合名.find({條件}).limit(number) #不寫number參數,默認讀取全部文檔
        #讀取3條學生信息
        db.stu.find().limit(3)
    • skip和limit合用

      • 不區分前後順序
        #查詢第5-9條學生信息
        db.stu.find().skip(4).limit(5) #至關於跳過4條數據,選5條
    • sort

      • 對結果集進行排序
        db.集合名稱.find({條件}).sort({字段:1,...}) #1表示升序,-1表示降序
        #根據性別降序,再根據年齡升序
        db.stu.find().sort({"gender":-1,"age":1})
    • count

      • 對結果集中文檔數目進行統計,返回整數
        db.集合名.find({條件}).count() 
        或者 
        db.集合名.count({條件})
        #統計年齡大於20的男生人數
        db.stu.count({"age":{$gt:20},"gender":1})
    • distinct

      • 對數據去重,返回的是一個列表
        db.集合名.distinct("字段名",{條件}) 

5、聚合(aggregate)

  • 聚合主要用於計算數據,相似sql中的sum()、avg()

    db.集合名.aggregate([{管道:{表達式}}...])
  • 管道

    • 文檔處理完畢後,經過管道進行下一次處理

    • 經常使用管道:

      • $group:將集合中的文檔分組,可用於統計結果
      • $match:過濾數據,只輸出符合條件的文檔
      • $project:修改輸入文檔的結構,如重命名、增長、刪除字段、建立計算結果
      • $sort:將輸入文檔排序後輸出
      • $limit:限制聚合管道返回的文檔數
      • $skip:跳過指定數量的文檔,並返回餘下的文檔
      • $unwind:將數組類型的字段進行拆分
  • 表達式

    • 處理輸入文檔並輸出

    • 語法:表達式:‘$字段名’

    • 經常使用表達式:

      • $sum:計算總和,$sum:'$字段'表示求和,注意$sum:1表示計數,
      • $avg:計算平均值
      • $min:獲取最小值
      • $max:獲取最大值
      • $push:在結果文檔中插入值到一個數組中(以列表的方式顯示字段值)
      • $first:根據資源文檔的排序獲取第一個文檔數據
      • $last:根據資源文檔的排序獲取最後一個文檔數據
  • $group

    • 文檔分組,用於統計結果
    • _id表示分組的依據,使用某個字段的格式爲'$字段'
      # 統計男、女生人數
      db.stu.aggregate([{$group:{"_id":'gender',"couter":{$sum:1}}}])
      #結果文檔中顯示_id和counter的值
    • _id按照null分組,會將集合中全部文檔分爲一組
      # 求學生總人數和平均年齡
      db.stu.aggregate([{$group:{_id:null,counter:{$sum:1},average_age:{$avg:"$age"}}}])
    • 使用$$ROOT能夠將文檔內容加入到結果集的數組中
      #統計男、女生信息
      db.stu.aggregate([{$group:{_id:"$gender",objects:{$push:"$$ROOT"}}}])
  • $match

    • 過濾數據,輸出符合條件文檔
      #查詢年齡大於20的學生
      db.stu.aggregate([{$match:{age:{$gt:20}}}])
      
      #查詢年齡大於20的男、女生人數
      db.stu.aggregate([{$match:{age:{$gt:20}}},{$group:{_id:"$gender",counter:{$sum:1}}}])
  • $project

    • 修改輸出文檔的結構
      #查找學生姓名、年齡
      db.stu.aggregate([{$project:{"_id":0,"name":1,"age":1}}])
      
      #查詢男生、女生人數,但僅輸出人數
      db.stu.aggregate([{$group:{_id:'$gender',counter:{$sum:1}}},{$project:{_id:0,counter:1}}])
  • $sort

    • 將輸入文檔排序後輸出
      #查詢學生信息,按年齡升序
      db.stu.aggregate([{$sort:{age:1}}])
      
      #查詢男生、女生人數,按人數降序
      db.stu.aggregate([{$group:{_id:'$gender',counter:{$sum:1}},{$sort:{counter:-1}}])
  • $limit

    • 限制聚合管道返回的文檔數
      #查詢2條學生信息
      db.stu.aggregate([{$limit:2}])
  • $skip

    • 跳過指定數量的文檔,並返回餘下的文檔,$skip和$limi合用時,注意先寫skip,再寫limit
      #查詢從第3條開始的學生信息
      db.stu.aggregate([{$skip:2}])
      
      #統計男生、女生人數,按人數升序,取第二條數據
      db.stu.aggregate([{$group:{_id:"$gender",counter:{$sum:1}}},{$sort:{"counter":1}},{$skip:1},{$limit:1}])
  • $unwind

    • 將文檔中的某一個數組類型字段拆分紅多條,每條包含數組中的一個值
      db.集合名稱.aggregate([{$unwind:'$字段名稱'}]) 

6、索引

  • 提高查詢速度

  • 建立大量數據

    for(var i=0;i<1000000;i++){db.stu.insert({name:'test'+i,num:i})}
  • 性能分析工具:explain("executionStats")

    查詢語句.explain("executionStats")

    'millis'後面顯示的是查詢時間,單位ms數據庫

  • 創建索引

    db.集合.ensureIndex({屬性:1或-1}) #1表示升序,-1表示降序,創建後的索引名稱爲"屬性_1"或者"屬性_-1"

    例如:db.stu.ensureIndex({name:1}),創建後的索引名稱爲"name_1"json

  • 創建惟一索引

    db.集合.ensureIndex({屬性:1},{"unique":true})
  • 創建聯合索引

    db.集合名.ensureIndex({屬性1:1,屬性2:1...})
  • 查看索引

    db.集合名.getIndexes()
  • 刪除索引

    db.集合名.dropIndex("索引名稱") 

7、數據庫安全

爲了更安全的訪問mongodb,須要訪問者提供用戶名和密碼,因而須要在mongodb中建立用戶。mongodb數據庫採用了角色-用戶-數據庫的安全管理方式。數組

  • 經常使用系統角色以下:

    • root:只在admin數據庫中可用,超級帳號,超級權限
    • Read:容許用戶讀取指定數據庫
    • readWrite:容許用戶讀寫指定數據庫
  • 建立超級管理用戶:

    use admin #首先切換到admin數據庫
    
    db.createUser({
        user:'用戶名',
        pwd:'密碼',
        roles:[{role:'root',db:'admin'}]
    })
  • 啓用安全驗證

    • 修改配置文件( /etc/mongodb.conf)

      #noauth = true
      auth = true #開啓安全驗證
    • 重啓服務

      sudo service mongodb restart
    • 終端鏈接

      # sudo mongo -u '用戶名' -p '密碼' --authenticationDatabase '數據庫名' 
      sudo mongo -u 'admin' -p '密碼' --authenticationDatabase 'admin'
  • 普通用戶管理

    • 首先使用超級管理員登錄,而後再進行用戶管理操做

    • 建立普通用戶

      db.createUser({
          user:'用戶名',
          pwd:'密碼',
          roles:[{role:'readWrite',db:'數據庫名'}...] #數組裏能夠有多個角色文檔,好比用戶在不一樣的數據庫裏都有讀寫權限
      })
    • 查看當前數據庫的用戶

      show users
    • 修改用戶:能夠修改pwd、roles屬性

      db.updateUser('用戶名',{pwd:'新密碼',roles:[{'新角色'}...]})
    • 刪除用戶

      use admin  #切換到admin數據庫
      db.system.users.remove(條件)
    • 終端鏈接

       sudo mongo -u '用戶名' -p '密碼' --authenticationDatabase '數據庫名' 

8、複製

複製提供了數據的冗餘備份,並在多個服務器上存儲數據的副本,容許從硬件故障和服務中斷中恢復數據,可以實現無宕機維護(自動故障轉移與自動恢復)。安全

複製至少須要2個節點,其中1個爲主節點,其它均爲從節點。任何節點都可以成爲主節點。服務器

主節點負責全部寫入操做,從節點按期輪詢主節點獲取這些操做並執行這些操做,從而保證從節點的數據與主節點一致。app

  • 設置複製節點

    • 建立數據庫文件存放目錄(自定義)

      mkdir ~/Desktop/t1
      mkdir ~/Desktop/t2
    • 使用以下格式啓動mongod,若是在同一臺主機上,注意port不能相同,replSet的名稱必須是一致的(名稱能夠自定義)

      sudo mongod --bind_ip 192.168.196.128 --port 27017 --dbpath ~/Desktop/t1 --replSet rs0
      sudo mongod --bind_ip 192.168.196.128 --port 27018 --dbpath ~/Desktop/t2 --replSet rs0
    • 鏈接主服務器(自定義一個)

      sudo mongo --host 192.168.196.128 --port 27017
    • 初始化

      rs.initiate()

      哪一個服務器執行初始化,哪一個服務器就做爲主節點,rs是mongo服務器中專門用於複本集操做的內置對象

    • 查看當前狀態

      rs.status()
    • 添加副本集

      rs.add("192.168.127.128:8899")
    • 鏈接從服務器

      sudo mongo --host 192.168.196.128 --port 27018
    • 從服務器設置

      rs.slaveOk()

      主服務器插入數據,從服務器就能夠讀取數據了

    • 刪除從節點

      rs.remove('192.168.196.128:27018') #須要在主服務器操做

      關閉主服務器後再從新啓動,會發現原來的從服務器變爲了主服務器,新啓動的服務器(原來的主服務器)變爲了從服務器,可是注意從新設置rs.slaveOk()

9、備份與恢復

  • 備份

    • 語法

      sudo mongodump -h 服務器地址 -d 須要備份的數據庫 -o 備份數據存放目錄
      mkdir ~/Desktop/test1_bak #建立存放備份數據的目錄
      sudo mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1_bak
  • 恢復

    • 語法

      sudo mongorestore -h 服務器地址 -d 恢復後數據庫名 --dir 備份數據所在位置
      sudo mongorestore -h 192.168.196.128:27017 -d test2 --dir ~/Desktop/test1_bak/test1

10、python交互

  • 安裝pymongo包

    sudo pip3 install pymongo
  • 引入包

    import pymongo
  • 創建鏈接並建立客戶端

    有安全認證:client=MongoClient("mongodb://用戶名:密碼@host:27017/數據庫名稱")
    無安全認證:client=MongoClient("mongodb://localhost: 27017")
  • 得到數據庫(以test數據庫爲例)

    db = client.數據庫名
    例如:db = client.test
  • 得到集合stu

    stu = db.stu
  • 數據操做

    • 查詢

      • find_one 查找單個文檔
        stu1 = stu.find_one({條件}) #返回一條文檔,字典類型
      • find 查找多個文檔
        cursor = stu.find({條件}) #返回迭代器對象cursor
        #方式1:用for循環迭代取值
        for s in cursor:
        print(s) #字典類型
        
        #方式2:用next取值
        s1 = next(cursor)
        s2 = next(cursor)
        ...
    • 插入

      • insert_one 插入一條文檔
        stu.insert_one(文檔)
      • insert_many 插入多條文檔
        stu.insert_many([文檔1,文檔2...])
    • 更新

      • update 更新匹配到的第一條整條文檔
        stu.update({條件},文檔) #注意條件中的數字必定要寫成字符串類型
      • update_one 與$set一塊兒使用,指定屬性修改匹配到的第一條文檔
        stu.update_one({條件},{$set:{文檔}})
      • update_many 與$set一塊兒使用,指定屬性修改多條文檔
        stu.update_many({條件},{$set:{文檔}})
    • 刪除

      • delete_one 刪除單條文檔
        stu.delete_one({條件})
      • delete_many 刪除多條文檔
        stu.delete_many({條件})
相關文章
相關標籤/搜索