03-數據庫MongoDB[Python]

一、MongoDB簡介

  • 概述
    MongoDB是一個基于分布式文件存儲的數據庫,由C++語言編寫。旨在為WEB應用提供可擴展的高性能數據存儲解決方案。

    MongoDB介于關系型數據和非關系型數據庫之間,是非關系數據庫當中功能最豐富,最像關系數據庫的。他支持的數據結構非常松散,類似json格式,因此可以存儲比較復雜的數據類型。

    MongoDB最大的特點是他支持的查詢語言非常強大,其語法有點類似于面向對象的查詢語言,幾乎可以實現類似關系數據庫表單查詢的絕大部分功能,而且還支持對數據建立索引。

  • MySQL
    關系型數據庫。 查詢語句是使用傳統的sql語句,擁有較為成熟的體系,成熟度很高。 關系型數據庫遵循ACID規則 開源數據庫的份額在不斷增加,mysql的份額頁在持續增長。 缺點:在海量數據處理的時候效率會顯著變慢。

    數據庫事務必須具備ACID特性,ACID是Atomic原子性,Consistency一致性,Isolation隔離性,Durability持久性。
    數據的持久存儲,尤其是海量數據的持久存儲,還是需要一種關系數據庫。

  • MongoDB
    非關系型數據庫(nosql ),屬于文檔型數據庫。存儲方式:虛擬內存+持久化。
    查詢語句:是獨特的MongoDB的查詢方式。
    適合場景:事件的記錄,內容管理或者博客平臺等等。
    數據處理:數據是存儲在硬盤上的,只不過需要經常讀取的數據會被加載到內存中,將數據存儲在物理內存中,從而達到高速讀寫。
    成熟度與廣泛度:新興數據庫,成熟度較低,Nosql數據庫中最為接近關系型數據庫,比較完善的DB之一,適用人群不斷在增長。
    優勢: 快速!在適量級的內存的MongoDB的性能是非常迅速的,它將熱數據存儲在物理內存中,使得熱數據的讀寫變得十分快, 高擴展, json的存儲格式!

    文檔的數據庫: 即可以存放xml、json、bson類型系那個的數據。這些數據具備自述性(self-describing),呈現分層的樹狀數據結構。數據結構由鍵值(key=>value)對組成。

  • 關系型數據庫和非關系型數據庫的區別
    關系型數據庫通過外鍵關聯來建立表與表之間的關系;
    非關系型數據庫通常指數據以對象的形式存儲在數據庫中,而對象之間的關系通過每個對象自身的屬性來決定;

    學生: 張三
    性別: 男
    科目: 語文
    成績: 80
    
    關系型數據庫:
      // 學生表
      create table student(id int primary key, name char(50), sex char(10))
      // 成績表,stuid存儲的是學生表中對應的主鍵,用于表的關聯
      create table score(id int primary key, name char(20),grade int,stuid int, foreign key(stuid) references student(id))
    
    非關系型數據庫:
    {
      "name":"張三",
      "sex":"男",
      "score":{
        "name":"語文",
        "grade": 80
      }
    }
    
    

    關系型數據庫SQLite、Oracle、mysql
    非關系型數據庫 MongoDb、redis

  • MySQL和MongoDB的區別
    數據庫: 容器,不管是mysql還是mongodb,一個單一的服務器都可以管理多個數據庫;
    集合:是一組mongodb的文件,等價于mysql中的table,集合中文檔可以有不同的字段,也可以有不同的數據類型;

MySQL和MongoDB的區別

二、MongoDB安裝和卸載

  • 卸載

    sudo apt-get autoremove mongodb
    sudo apt-get autoclean mongodb
    
    // 清除殘留數據
    dpkg -l |grep ^rc|awk '{print $2}' |tr ["\n"] [" "]|sudo xargs dpkg -P   
    
    
  • 安裝

    第1步 – 導入公鑰**
      Ubuntu軟件包管理器apt(高級軟件包工具)需要軟件分銷商的GPG密鑰來確保軟件包的一致性和真實性。 執行此下面的命令將MongoDB密鑰導入到您的服務器:
      sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5
    
    第2步 – 創建源列表文件MongoDB
      檢查URL http://repo.mongodb.org/apt/ubuntu/dists/。
      如果您在該網頁上看到一個目錄“bionic”,則將下述命令中的單詞“xenial”替換為“bionic”一詞,
    【原因:MongoDB尚未發布Bionic Beaver軟件包,但Xenial軟件包在Ubuntu 18.04 LTS上運行良好】
      執行以下命令在/etc/apt/sources.list.d/中創建一個MongoDB列表文件:
      echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.6 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.6.list
    
    第3步 – 更新存儲庫
      使用apt命令更新存儲庫:
      sudo apt-get update
      說明:執行完會提示一些失敗,不用在意
    
    第4步 – 安裝MongoDB
      執行以下命令來安裝MongoDB:
      sudo apt-get install -y mongodb
    
    第5步:啟動MongoDB
      執行以下命令啟動MongoDB并將其添加為在啟動時啟動的服務
      sudo systemctl start mongodb
    
        如果執行完這一步終端沒有任何輸出,則說明是正確的
        如果啟動的時候提示:Failed to start mongod.service: Unit mongodb.service not found.
        解決辦法如下:
        1創建配置文件:
          cd /etc/systemd/system/
          sudo vi mongodb.service
        2.在里面追加文本:
          [Unit]
          Description=High-performance, schema-free document-oriented database
          After=network.target
          [Service]
          User=mongodb
          ExecStart=/usr/bin/mongod --quiet --config /etc/mongodb.conf
          [Install]
          WantedBy=multi-user.target
        3.退出
          :wq
        4.啟動服務
          sudo systemctl start mongodb
          sudo systemctl status mongodb
        5.設置開機自啟動
          sudo systemctl enable mongodb
    
    第6步:登錄MongoDB
        mongo
    
          如果出現錯誤全局初始化失敗:BadValue無效或無用戶區域設置。 請確保LANG和/或LC_ *環境變量設置正確,請嘗試命令:
          export LC_ALL=C
    
    

三、MongoDB之數據庫操作

  • 創建數據庫

    # mongodb
    use DATABASE_NAME
    注意:如果指定的數據庫DATABASE_NAME不存在,則該命令將創建一個新的數據庫,否則返回現有的數據庫
    
    # mysql中
    創建數據庫:create database basename;
    切換數據庫:use basename;
    
    

    admin:從權限的角度來說,是root的數據庫
    ? local:本地數據
    ? config:配置,用于保存MongoDB的配置信息

  • 檢查當前選擇的數據

    db
    
    

    默認的數據庫test

  • 顯示數據庫列表

    show dbs 
    
    
  • 刪除數據庫

    // 默認進入數據庫是test
    db.dropDatabase()
    
    

    注意:默認刪除當前正在工作的數據庫

四、MongoDB之集合操作

類似于MySQL中的表。
集合存在于數據庫中,集合沒有固定的結構,意味著可以對集合插入不同格式和不同類型的數據,但是盡量插入集合的時候保證數據的關聯性。

  • 創建集合

    集合名的規范:
      a.不能空字符串
      b.集合名不能含有\0【空字符】,表示集合名的結尾
      c.集合名不能以"system."開頭,為系統集合保留的關鍵字
      d.不能含有保留字符,千萬不能含有$
    
    語法:
      // name的類型為String,是要創建的集合的名稱
      // options的類型是Document,是一個文檔,指定相應的大小和索引,是可選參數
      // 在插入文檔時,MongoDB首先檢查上限集合capped字段的大小,然后檢查max字段
      db.createCollection(name, options)
    
    例如:
      // 沒有options選項的集合創建
      db.createCollection("myCollection")
    
      // 有options選項的集合的創建
      db.createCollection("mycol",{capped:true,autoIndexId:true,size:1024,max:10000})
    
    
    選項列表
  • 顯示當前數據庫中的集合

    show collections
    
    
  • 刪除集合

    語法:
      // 如果選定的集合成功刪除,drop()方法將返回true,否則返回false
      db.COLLECTION_NAME.drop()
    
    例如:
      db.mycollection.drop()
    
    

五、MongoDB之文檔操作

  • 文檔概念
    文檔:相當表中的一條記錄【實體】
    是一組鍵值對,文檔不需要設置相同的字段,并且相同的字段不需要相同的數據類型

    注意: 
    a.文檔中的鍵值對是有序的
    b.文檔中值除了字符串之外,還可以是其他數據類型【嵌套一個文檔】
    c.嚴格區分大小寫和數據類型的,mycol myCol
    d.文檔中不能有重復的鍵
    e.文檔中的鍵基本都是用字符串表示的
    
    
    文檔中鍵的命名:
    a.鍵不能包含\0
    b.$和.有特殊含義
    c.以下劃線開頭的鍵是保留的,盡量不要使用下劃線開頭
    
    
  • 插入文檔

    語法:
      // 在插入的文檔中,如果不指定_id參數,那么 MongoDB 會為此文檔分配一個唯一的ObjectId
      // _id為集合中的每個文檔唯一的12個字節的十六進制數。
      db.COLLECTION_NAME.insert(document)
    
    例如:
      // 插入一個
      db.mycol.insert({id:101, name:'lisi', age:20})
      db.mycol.insert({ 
         item: "canvas", 
         num: 100, 
         tags: ["cotton"], 
         size: { 
              h: 20,
              w: 30, 
          } 
      })
    
      // 插入多個(注意方括號)
      db.mycol.insert( [{id:102, name:'wagnwu', age:18}, {id:103, name:'zhaoliu', age:21}, {id:104, name:'tianqi', age:19}] )
    
      // 查看已插入的文檔
      db.mycol.find()
      { "_id" : ObjectId("5b8b59cb5bd1df1fc73dcdc6"), "id" : 101, "name" : "lisi", "age" : 20 }
    
      // 查看已插入的文檔
      db.mycol.find().pretty()
      {
      "_id" : ObjectId("5b8b59cb5bd1df1fc73dcdc6"),
      "id" : 101,
      "name" : "lisi",
      "age" : 20
      }
    
    
  • 查詢文檔

    語法:
      // 基本操作
      db.COLLECTION_NAME.find(document)
       // 以格式化的方式返回查詢結果
       db.COLLECTION_NAME.find(document).pretty()
    
    注意: 
      find() 將以非結構化的方式返回查詢結果
    
     例如: 
      // 顯示所有文檔
      db.mycol.find()
    
      // 默認將所有文檔顯示,為了限制列表,需要顯示的字段設置為1,不顯示的設置為0
      db.mycol.find( {'name':'liming'}, {'name':1, 'age': 1} )
      db.mycol.find( {'name':'liming'}, {'age':0} )
    
      // 限制字段顯示
      db.check.find({},{'_id':1,'title':1})
    
    
  • 查詢文檔(條件查詢)

    - 等于{ <key>:<value> }
      db.mycol.find({'name':'yhy'} ).pretty()
    
    - 小于 { <key>: {$lt:<value>} }
      db.mycol.find( {'age': {$lt:18}} ).pretty()
    
    - 小于等于 { <key>: {$lte:<value>} }
      db.mycol.find( {'age': {$lte:18}} ).pretty()
    
    - 大于 { <key>: {$gt:<value>} }
      db.mycol.find( {'age': {$gt:18}} ).pretty()
    
    - 大于等于 { <key>: {$gte:<value>} }
      db.mycol.find( {'age': {$gte:18}} ).pretty()
    
    - 不等于 { <key>: {$ne:<value>} }
      db.mycol.find( {'age': {$ne:18}} ).pretty()
    
    - 并列關系(and)
      在find()方法中,如果通過使用 ',' 將它們分開傳遞多個鍵,則 MongoDB 將其視為AND條件
      db.mycol.find(
        {
          $and: [
            {key1: value1}, {key2: value2}
          ]
        }
      )
    
    - 或者關系(or)
      db.mycol.find(
        {
          $or: [
            {key1: value1}, {key2: value2}
          ]
        }
      )
    
    
  • 更新文檔

    update()更新現有文檔中的值,語法:
      db.COLLECTION_NAME.update(SELECTION_CRITERIA, UPDATED_DATA)
    例如:
      // update默認只更新一個文檔,如果要更新多個文檔,則添加參數{multi:true})
      db.check.update( {'title': 'MongoDB Guide'}, {$set: {'title': 'mongo'}} )
      db.check.update( {'title': 'MongoDB Guide'}, {$set: {'title': 'mongo'}, $set: {'say': 'hello'}} )
      db.check.update( {'title': 'MongoDB Guide'}, {$set: {'title': 'mongo'}}, {multi: true} )
    
    save()用傳遞的文檔數據替換現有文檔,語法:  
      db.COLLECTION_NAME.save({_id:ObjectId(),NEW_DATA})
    例如:
      db.check.save( {'_id':102, 'title':'hello', 'by':'lalala'} )  
    
    
  • 刪除文檔

    語法:
      db.COLLECTION_NAME.remove(DELLETION_CRITTERIA)
    
     例如:
       db.check.remove( {'_id':100} )
    
    

六、MongoDB之查詢

  • 投影
    查詢過程中,只顯示指定的字段

    語法:
      db.COLLECTION_NAME.find({},{KEY:1})
    
    例如:
      db.mycol.find( {}, {'title':1, _id:0} )
    
    

    在執行find()方法時,始終都會顯示_id字段,如果不想要此字段,則需要將其設置為0

  • 限制篩選記錄

    limit()限制MongoDB要返回的記錄數,根據指定的參數返回記錄數
    語法:
      db.COLLECTION_NAME.find().limit(NUMBER)
    例如: 
      // 在查詢文檔時僅顯示兩個文檔
      db.mycol.find({},{"title":1,_id:0}).limit(2)
    
    skip() 方法跳過指定數量的數據
    語法:
      // 注意:skip()方法中的默認值為0。
      db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
    例如:
      db.mycol.find({},{"title":1,_id:0}).limit(1).skip(2)
    
    
  • 對查詢記錄排序

     語法:
        // 使用指定順序進行排序,1表示升序,-1表示降序
        db.COLLECTION_NAME.find().sort({KEY:1})
      例如:
         db.mycol.find({},{"title":1,_id:0}).sort({"title":-1})
    
    
  • 管道的概念
    MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢后將結果傳遞給下一個管道處理。管道操作是可以重復的。

    $project:修改輸入文檔的結構。可以用來重命名、增加或刪除域,也可以用于創建計算結果以及嵌套文檔
      db.article.aggregate( [ {$project:{by_user:1, title:1}} ] )
    
    $limit:用來限制MongoDB聚合管道返回的文檔數
      db.article.aggregate( [ {$project:{by_user:1, title:1}}, {$limit: 2} ] )  
    
    $skip:在聚合管道中跳過指定數量的文檔,并返回余下的文檔
      db.article.aggregate( [ {$project:{by_user:1, title:1}}, {$skip: 1} ] )
      db.article.aggregate( [ {$project:{by_user:1, title:1}}, {$limit:2},{$skip: 1} ] ) 
    
    $group:將集合中的文檔分組,可用于統計結果
      db.article.aggregate( [ {$group: {_id:'$by_user', num:{$sum:'$likes'}}} ] )
    
    $sort:將輸入文檔排序后輸出
      db.article.aggregate( [ {$group: {_id:'$by_user', num:{$sum:'$likes'}}},{$sort: {'num':-1}} ] )
    
    
  • 分組與聚合函數查詢

    aggregate()語法:
      db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
    
    - $sum 從集合中的所有文檔中求出定義的值
      // 計算每個作者所寫的文章點贊數
      db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
      // 計算每個作者所寫文檔數量
      // select by_user, count(*) from article group by by_user
      db.article.aggregate([ { $group: {_id:'$by_user', num:{$sum:1}} } ])
    
    - $avg 計算集合中所有文檔的所有給定值的平均值
      db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
    
    - $max 從集合中的所有文檔獲取相應值的最大值
      // _id:'$by_user',對應按照by_user分組
      db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
      // _id對應一個常量,即所有數據的操作
      db.article.aggregate([ { $group:{_id:'max', num_likes:{$max:'$likes'}} } ])
    
    - $min 從集合中的所有文檔獲取相應值的最小值
      db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
    
    - 例如:
      db.article.aggregate([{$group:{'_id':'$by_user','num_tutorial':{$sum:1}}}])
    
    

七、MongoDB之關聯關系

MongoDB中的關系表示各個文檔在邏輯上的相互關聯。關系可以通過嵌入式和引用方法建模。 這種關系可以是1:1,1:N,N:1或N:N。

假設有一種情況:要存儲用戶的地址。一個用戶可以擁有多個地址,這就是1:N關系。

// 用戶user文檔
{
   "_id":10999110,
   "name": "Maxsu",
   "contact": "13800138000",
   "dob": "1992-10-11"
}

// 地址文檔
{
   "_id":12200,
   "building": "Hainan Building NO.2100",
   "pincode": 571100,
   "city": "Haikou",
   "province": "Hainan"
}

嵌入式關系建模
在嵌入式方法中,我們將地址(address)文檔嵌入到用戶(user)文檔中

{
   "_id": 21000100,
   "contact": "13800138000",
   "dob": "1991-11-11",
   "name": "Maxsu",
   "address": [
      {
         "building": "Hainan Building NO.2100",
         "pincode": 571100,
         "city": "Haikou",
         "province": "Hainan"
      },
      {
         "building": "Sanya Building NO.2100",
         "pincode": 572200,
         "city": "Sanya",
         "province": "Hainan"
      },
   ]
}

該方法將所有相關數據保存在單個文檔中,這使得檢索和維護更容易。
可以使用單個查詢來在整個文檔檢索:
 db.users.find( {"name":"Maxsu"},{"address":1, "name":1} )

在上述查詢中,db和users分別是數據庫和集合。缺點是如果嵌入式文檔的大小如果不斷增長,可能會影響讀/寫性能。

建模參考關系
這是設計規范化關系的方法。 
在這種方法中,用戶和地址文件將分別維護,但用戶文檔將包含一個將引用地址文檔的id字段的字段。
{
   "_id":ObjectId("52ffc33321332111sdfaf"),
   "contact": "13800138000",
   "dob": "1991-11-11",
   "name": "Maxsu",
   "address_ids": [
      ObjectId("123123"),
      ObjectId("123412")
   ]
}
用戶文檔包含對應地址的ObjectId的數組字段address_ids。 
使用這些ObjectIds,我們可以從那里查詢地址文件并獲取地址詳細信息。 
使用這種方法,需要兩個查詢:首先從用戶文檔獲取address_ids字段,然后從地址集中獲取這些地址。
var result = db.users.find({"name":"Maxsu"},{"address_ids":1})
var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})

八、MongoDB與Python的交互

- 安裝
pip3 install pymongo

- 使用
import pymongo
from pymongo import  MongoClient
from bson.objectid import ObjectId

#1.建立連接
#創建MongoClient的對象
#方式一
#特點:可以連接默認的主機和端口號
#client = MongoClient()
#方式二
#明確指明主機和端口號
#client = MongoClient('localhost',27017)
#client = MongoClient(host='localhost',port=27017)
#方式三
#使用MongoDB URI的
client = MongoClient('mongodb://localhost:27017')

#2.獲取數據庫
#MongoDB的一個實例可以支持多個獨立的數據庫
#可以通過MongoClient的對象的屬性來訪問數據庫
#方式一
db = client.test
print(db)
#方式二
#db = client['test']

#3.獲取集合
#集合是存儲在MongoDb中的一組文檔,可以類似于MySQl中的表
#方式一
collection = db.stuents
#方式二
#collection = db['students']
"""
注意:
MongoDB中關于數據庫和集合的創建都是懶創建
以上的操作在MongoDB的服務端沒有做任何操作
當第一個文檔被插入集合的時候才會創建數據庫和集合
"""

#4.文檔
#在pymongo中使用字典來表示文檔
student1 = {
    'id':'20180101',
    'name':'jack',
    'age':20,
    'gender':'male'
}

#5.插入文檔
#5.1insert()
#插入單條數據
#注意:MongoDb會自動生成一個ObjectId,insert函數的返回值為objectid
result = collection.insert(student1)
print(result)

#插入多條數據
student2 = {
    'id':'20180530',
    'name':'tom',
    'age':30,
    'gender':'male'
}
student3 = {
    'id':'20180101',
    'name':'bob',
    'age':18,
    'gender':'male'
}
#result = collection.insert([student2,student3])

#6.查詢文檔
#6.1
#find_one()
result = collection.find_one({'name':'jack'})
print(type(result))    #<class 'dict'>
print(result)

#6.2find()
#需求:查詢年齡為20的數據
results = collection.find({'age':20})
print(results)
#Cursor相當于是一個生成器,只能通過遍歷的方式獲取其中的數據
for r in results:
    print(r)

#6.3其他用法
#a.count()
#統計所有數據的條數
count1 = collection.find().count()
#統計制定條件的數據條數
count1 = collection.find({'age':20}).count()

#7.更新文檔
#7.1update()
conditon = {'name':'jack'}
student = collection.find_one(conditon);
student['age'] = 30
result = collection.update(conditon,student)

#7.2update_one()
conditon = {'name':'jack'}
student = collection.find_one(conditon);
student['age'] = 30
result = collection.update_one(conditon,{'$set':student})
print(result.matched_count,result.modified_count)

#7.3update_many()
#查詢年齡大于20的數據,然后講年齡增加1
conditon = {'age':{'$gt':20}}
result = collection.update_one(conditon,{'$inc':{'age':1}})
print(result.matched_count,result.modified_count)

#8.刪除文檔
#8.1remove()
#將符合條件的所有的數據全部刪除
result = collection.remove({'name':'rose'})

#8.2delete_one()
result = collection.delete_one({'name':'rose'})

#8.3delete_many()
result = collection.delete_many({'name':'rose'})

備注: 默認MongoDB是綁定127.0.0.1,連接遠程是連接不了的。
編輯MongoDB配置文件: sudo vi /etc/mongodb.conf
找到 bind_ip = 127.0.0.1 改為 bind_ip = 0.0.0.0

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一、MongoDB簡介 概述MongoDB是一個基于分布式文件存儲的數據庫,由C++語言編寫。旨在為WEB應用提供...
    EndEvent閱讀 1,175評論 1 4
  • 一、MongoDB簡介 概述MongoDB是一個基于分布式文件存儲的數據庫,由C++語言編寫。旨在為WEB應用提供...
    王梓懿_1fbc閱讀 503評論 0 3
  • 關于Mongodb的全面總結 MongoDB的內部構造《MongoDB The Definitive Guide》...
    中v中閱讀 32,022評論 2 89
  • 一、MongoDB簡介 概述MongoDB是一個基于分布式文件存儲的數據庫,由C++語言編寫。旨在為WEB應用提供...
    fly5閱讀 300評論 0 0
  • 一、MongoDB簡介 概述MongoDB是一個基于分布式文件存儲的數據庫,由C++語言編寫。旨在為WEB應用提供...
    未央_m閱讀 719評論 0 1