1. 程式人生 > >python使用pymongo讀寫mongodb

python使用pymongo讀寫mongodb

轉載請註明出處:python使用pymongo讀寫mongodb

準備工作

在開始之前,請確保已經安裝好了MongoDB並啟動了其服務,並且安裝好了Python的PyMongo庫。

PyMongo介紹

Python 要連線 MongoDB 需要 MongoDB 驅動,這裡我們使用 PyMongo 驅動來連線。

官方文件
http://api.mongodb.com/python/current/api/pymongo/collection.html

pip 安裝

pip 是一個通用的 Python 包管理工具,提供了對 Python 包的查詢、下載、安裝、解除安裝的功能。

安裝 pymongo:

$ python3 -m pip3 install pymongo

也可以指定安裝的版本:

$ python3 -m pip3 install pymongo==3.5.1

更新 pymongo 命令:

$ python3 -m pip3 install --upgrade pymongo

easy_install 安裝

舊版的 Python 可以使用 easy_install 來安裝,easy_install 也是 Python 包管理工具。

$ python -m easy_install pymongo

更新 pymongo 命令:

$ python -m easy_install -U pymongo

測試 PyMongo

接下來我們可以建立一個測試檔案 demo_test_mongodb.py,程式碼如下:

demo_test_mongodb.py 檔案程式碼:

#!/usr/bin/python3
 
import pymongo

執行以上程式碼檔案,如果沒有出現錯誤,表示安裝成功。

連線MongoDB

連線MongoDB時,我們需要使用PyMongo庫裡面的MongoClient。一般來說,傳入MongoDB的IP及埠即可,其中第一個引數為地址host,第二個引數為埠port(如果不給它傳遞引數,預設是27017):

沒有許可權auth認證的連線方式

import pymongo
client = pymongo.MongoClient(host='localhost', port=27017)

這樣就可以建立MongoDB的連線物件了。
另外,MongoClient的第一個引數host還可以直接傳入MongoDB的連線字串,它以mongodb開頭,例如:

client = MongoClient('mongodb://localhost:27017/')

這也可以達到同樣的連線效果。

需要auth許可權認證的連線方式

需要注意mongodb資料庫本身的版本
mongodb3.0之前的加密方式為MONGODB-CR
示例如下:

from pymongo import MongoClient
client = MongoClient('example.com',
                     username='user',
                      password='password',
                      authMechanism='MONGODB-CR')

uri = "mongodb://user:[email protected]/?authSource=the_database&authMechanism=MONGODB-CR"
client = MongoClient(uri)

如果不指定加密方式,PyMongo 會自動使用MONGODB-CR方式連線3.0之前的mongodb服務和使用SCRAM-SHA-1方式連線3.0到3.6的mongodb服務端,使用 SCRAM-SHA-1 or SCRAM-SHA-256連線mongodb4.0的服務端。

使用程式碼如下:

uri = "mongodb://user:[email protected]/default_db?authSource=admin"
client = MongoClient(uri)

更多許可權相關的連線和加密方式參考:
http://api.mongodb.com/python/current/examples/authentication.html

指定資料庫

MongoDB中可以建立多個數據庫,接下來我們需要指定操作哪個資料庫。這裡我們以test資料庫為例來說明,下一步需要在程式中指定要使用的資料庫:

db = client.test

這裡呼叫client的test屬性即可返回test資料庫。當然,我們也可以這樣指定:

db = client['test']

這兩種方式是等價的。

指定集合

MongoDB的每個資料庫又包含許多集合(collection),它們類似於關係型資料庫中的表。
下一步需要指定要操作的集合,這裡指定一個集合名稱為students。與指定資料庫類似,指定集合也有兩種方式:

collection = db.students
collection = db['students']

這樣我們便聲明瞭一個Collection物件。

新增記錄

單條插入

# 示例一:指定 _id,如果重複,會產生異常
ID = 'firstRecord'
insertDate = '2017-08-28'
count = 10
insert_record = {'_id':ID, 'endDate': insertDate, 'count': count}
insert_res = db_coll.insert_one(insert_record)
print(f"insert_id={insert_res.inserted_id}: {insert_record}")
# 結果:insert_id=firstRecord: {'_id': 'firstRecord', 'endDate': '2017-08-28', 'count': 10}


# 示例二:不指定 _id,自動生成
insertDate = '2017-10-10'
count = 20
insert_record = {'endDate': insertDate, 'count': count}
insert_res = db_coll.insert_one(insert_record)
print(f"insert_id={insert_res.inserted_id}: {insert_record}")
# 結果:insert_id=59ad356d51ad3e2314c0d3b2: {'endDate': '2017-10-10', 'count': 20, '_id': ObjectId('59ad356d51ad3e2314c0d3b2')}

批量插入

# 更高效,但要注意如果指定_id,一定不能重複
# ordered = True,遇到錯誤 break, 並且丟擲異常
# ordered = False,遇到錯誤 continue, 迴圈結束後丟擲異常
insertRecords = [{'i':i, 'date':'2017-10-10'} for i in range(10)]
insertBulk = db_coll.insert_many(insertRecords, ordered = True)
print(f"insert_ids={insertBulk.inserted_ids}")
# 結果:insert_ids=[ObjectId('59ad3ba851ad3e1104a4de6d'), ObjectId('59ad3ba851ad3e1104a4de6e'), O

查詢記錄:find

指定返回哪些欄位

# 示例一:所有欄位
# select * from galance20170801
searchRes = db_coll.find()
# 或者searchRes = db_coll.find({}) 
familys=[]
for x in searchRes:
     familys.append(x)
     print(f"userId={x['userId']} " f"dealed={x['dealed']}")
return familys


# 示例二:用字典指定要顯示的哪幾個欄位
# select _id,key from galance20170801
queryArgs = {}
projectionFields = {'_id':True, 'key':True}  # 用字典指定
searchRes = db_coll.find(queryArgs, projection = projectionFields)
# 結果{'_id': 'B01EYCLJ04', 'key': 'pro audio'}


# 示例三:用字典指定去掉哪些欄位
queryArgs = {}
projectionFields = {'_id':False, 'key':False}  # 用字典指定
searchRes = db_coll.find(queryArgs, projection = projectionFields)
# 結果{'activity': False, 'avgStar': 4.3,  'color': 'Yellow & Black', 'date': '2017-08-01'}


# 示例四:用列表指定要顯示哪幾個欄位
# select _id,key,date from galance20170801
queryArgs = {}
projectionFields = ['key','date']  # 用列表指定,結果中一定會返回_id這個欄位
searchRes = db_coll.find(queryArgs, projection = projectionFields)
# 結果{'_id': 'B01EYCLJ04', 'date': '2017-08-01', 'key': 'pro audio'}

指定查詢條件

比較:=,!=,>, <, >=, <=
$ne:不等於(not equal)
$gt:大於(greater than)
$lt:小於(less than)
$lte:小於等於(less than equal)
$gte:大於等於(greater than equal)

# 示例一:相等
# select _id,key,sales,date from galance20170801 where key = 'TV & Video'
queryArgs = {'key':'TV & Video'}
projectionFields = ['key','sales','date']
searchRes = db_coll.find(queryArgs, projection = projectionFields)
# 結果:{'_id': '0750699973', 'date': '2017-08-01', 'key': 'TV & Video', 'sales': 0}


# 示例二:不相等
# select _id,key,sales,date from galance20170801 where sales != 0
queryArgs = {'sales':{'$ne':0}}
projectionFields = ['key','sales','date']
searchRes = db_coll.find(queryArgs, projection = projectionFields)
# 結果:{'_id': 'B01M996469', 'date': '2017-08-01', 'key': 'stereos', 'sales': 2}

# 示例三:大於 
# where sales > 100
queryArgs = {'sales':{'$gt':100}}
# 結果:{'_id': 'B010OYASRG', 'date': '2017-08-01', 'key': 'Sound Bar', 'sales': 124}

# 示例四:小於 
# where sales < 100
queryArgs = {'sales':{'$lt':100}}
# 結果:{'_id': 'B011798DKQ', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 0}

# 示例五:指定範圍 
# where sales > 50 and sales < 100
queryArgs = {'sales':{'$gt':50, '$lt':100}}
# 結果:{'_id': 'B008D2IHES', 'date': '2017-08-01', 'key': 'Sound Bar', 'sales': 66}

# 示例六:指定範圍,大於等於,小於等於 
# where sales >= 50 and sales <= 100
queryArgs = {'sales':{'$gte':50, '$lte':100}}
# 結果:{'_id': 'B01M6DHW26', 'date': '2017-08-01', 'key': 'radios', 'sales': 50}

and

# 示例一:不同欄位,並列條件 
# where date = '2017-08-01' and sales = 100
queryArgs = {'date':'2017-08-01', 'sales':100}
# 結果:{'_id': 'B01BW2YYYC', 'date': '2017-08-01', 'key': 'Video', 'sales': 100}

# 示例二:相同欄位,並列條件 
# where sales >= 50 and sales <= 100
# 正確:queryArgs = {'sales':{'$gte':50, '$lte':100}}
# 錯誤:queryArgs = {'sales':{'$gt':50}, 'sales':{'$lt':100}}
# 結果:{'_id': 'B01M6DHW26', 'date': '2017-08-01', 'key': 'radios', 'sales': 50}

##or

# 示例一:不同欄位,或條件 
# where date = '2017-08-01' or sales = 100
queryArgs = {'$or':[{'date':'2017-08-01'}, {'sales':100}]}
# 結果:{'_id': 'B01EYCLJ04', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 0}

# 示例二:相同欄位,或條件 
# where sales = 100 or sales = 120
queryArgs = {'$or':[{'sales':100}, {'sales':120}]}
# 結果:
#    {'_id': 'B00X5RV14Y', 'date': '2017-08-01', 'key': 'Chargers', 'sales': 120}
#    {'_id': 'B0728GGX6Y', 'date': '2017-08-01', 'key': 'Glasses', 'sales': 100}

in,not in,all

# 示例一:in 
# where sales in (100,120)
# 這個地方一定要注意,不能用List,只能用元組,因為是不可變的
# 如果用了 {'$in': [100,120]},就會出現異常:TypeError: unhashable type: 'list'
queryArgs = {'sales':{'$in': (100,120)}}
# 結果:
#    {'_id': 'B00X5RV14Y', 'date': '2017-08-01', 'key': 'Chargers', 'sales': 120}
#    {'_id': 'B0728GGX6Y', 'date': '2017-08-01', 'key': 'Glasses', 'sales': 100}

# 示例二:not in 
# where sales not in (100,120)
queryArgs = {'sales':{'$nin':(100,120)}}
# 結果:{'_id': 'B01EYCLJ04', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 0}

# 示例三:匹配條件內所有值 all 
# where sales = 100 and sales = 120
queryArgs = {'sales':{'$all':[100,120]}}  # 必須同時滿足
# 結果:無結果

# 示例四:匹配條件內所有值 all  
# where sales = 100 and sales = 100
queryArgs = {'sales':{'$all':[100,100]}}  # 必須同時滿足
# 結果:{'_id': 'B01BW2YYYC', 'date': '2017-08-01', 'key': 'Video', 'sales': 100}

欄位是否存在

# 示例一:欄位不存在
# where rank2 is null
queryArgs = {'rank2':None}
projectionFields = ['key','sales','date', 'rank2']
searchRes = db_coll.find(queryArgs, projection = projectionFields)
# 結果:{'_id': 'B00ACOKQTY', 'date': '2017-08-01', 'key': '3D TVs', 'sales': 0}

# mongodb中的命令
db.categoryAsinSrc.find({'isClawered': true, 'avgCost': {$exists: false}})

# 示例二:欄位存在
# where rank2 is not null
queryArgs = {'rank2':{'$ne':None}}
projectionFields = ['key','sales','date','rank2']
searchRes = db_coll.find(queryArgs, projection = projectionFields).limit(100)
# 結果:{'_id': 'B014I8SX4Y', 'date': '2017-08-01', 'key': '3D TVs', 'rank2': 4.0, 'sales': 0}

正則表示式匹配:$regex(SQL:like)

# 示例一:關鍵字key包含audio子串
# where key like "%audio%"
queryArgs = {'key':{'$regex':'.*audio.*'}}
# 結果:{'_id': 'B01M19FGTZ', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 1}

陣列中必須包含元素:$all

# 查詢記錄,linkNameLst是一個數組,指定linkNameLst欄位必須包含 'Electronics, Computers & Office' 這個元素。
db.getCollection("2018-01-24").find({'linkNameLst': {'$all': ['Electronics, Computers & Office']}})

# 查詢記錄,linkNameLst是一個數組,指定linkNameLst欄位必須同時包含 'Wearable Technology' 和 'Electronics, Computers & Office' 這兩個元素。
db.getCollection("2018-01-24").find({'linkNameLst': {'$all': ['Wearable Technology', 'Electronics, Computers & Office']}})

按陣列大小查詢

兩個思路:
第一個思路:使用$where(具有很大的靈活性,但是速度會慢一些)

# priceLst是一個數組, 目標是查詢 len(priceLst) < 3 
db.getCollection("20180306").find({$where: "this.priceLst.length < 3"})

關於$where,請參考官方文件:http://docs.mongodb.org/manual/reference/operator/query/where/。

第二個思路:判斷陣列中的某個指定索引的元素是否存在(會比較高效)
例如:如果要求 len(priceLst) < 3:就意味著 num[ 2 ]不存在

# priceLst是一個數組, 目標是查詢 len(priceLst) < 3 
db.getCollection("20180306").find({'priceLst.2': {$exists: 0}})

例如:如果要求 len(priceLst) > 3:就意味著 num[ 3 ]存在

# priceLst是一個數組, 目標是查詢 len(priceLst) > 3 
db.getCollection("20180306").find({'priceLst.3': {$exists: 1}})

限定數量:limit

# 示例一:按sales降序排列,取前100
# select top 100 _id,key,sales form galance20170801 where key = 'speakers' order by sales desc
queryArgs = {'key':'speakers'}
projectionFields = ['key','sales']
searchRes = db_coll.find(queryArgs, projection = projectionFields)
topSearchRes = searchRes.sort('sales',pymongo.DESCENDING).limit(100)

排序:sort

# 示例二:按sales降序,rank升序
# select _id,key,date,rank from galance20170801 where key = 'speakers' order by sales desc,rank
queryArgs = {'key':'speakers'}
projectionFields = ['key','sales','rank']
searchRes = db_coll.find(queryArgs, projection = projectionFields)
# sortedSearchRes = searchRes.sort('sales',pymongo.DESCENDING) # 單個欄位
sortedSearchRes = searchRes.sort([('sales', pymongo.DESCENDING),('rank', pymongo.ASCENDING)]) # 多個欄位
# 結果:
# {'_id': 'B000289DC6', 'key': 'speakers', 'rank': 3.0, 'sales': 120}
# {'_id': 'B001VRJ5D4', 'key': 'speakers', 'rank': 5.0, 'sales': 120}

統計:count

# 示例三:統計匹配記錄總數
# select count(*) from galance20170801 where key = 'speakers'
queryArgs = {'key':'speakers'}
searchResNum = db_coll.find(queryArgs).count()
# 結果:
# 106

修改記錄

# 根據篩選條件_id,更新這條記錄。如果找不到符合條件的記錄,就插入這條記錄(upsert = True)
updateFilter = {'_id': item['_id']}
updateRes = db_coll.update_one(filter = updateFilter,
                               update = {'$set': dict(item)},
                               upsert = True)
print(f"updateRes = matched:{updateRes.matched_count}, modified = {updateRes.modified_count}")


# 根據篩選條件,更新部分欄位:i是原有欄位,isUpdated是新增欄位
filterArgs = {'date':'2017-10-10'}
updateArgs = {'$set':{'isUpdated':True, 'i':100}}
updateRes = db_coll.update_many(filter = filterArgs, update = updateArgs)
print(f"updateRes: matched_count={updateRes.matched_count}, "
      f"modified_count={updateRes.modified_count} modified_ids={updateRes.upserted_id}")
# 結果:updateRes: matched_count=8, modified_count=8 modified_ids=None

刪除記錄

刪除一條記錄

# 示例一:和查詢使用的條件一樣
queryArgs = {'endDate':'2017-08-28'}
delRecord = db_coll.delete_one(queryArgs)
print(f"delRecord={delRecord.deleted_count}")
# 結果:delRecord=1

批量刪除

# 示例二:和查詢使用的條件一樣
queryArgs = {'i':{'$gt':5, '$lt':8}}
# db_coll.delete_many({})  # 清空資料庫
delRecord = db_coll.delete_many(queryArgs)
print(f"delRecord={delRecord.deleted_count}")
# 結果:delRecord=2

轉載請註明出處:python使用pymongo讀寫mongodb

參考連結:
http://www.runoob.com/python3/python-mongodb.html
https://juejin.im/post/5addbd0e518825671f2f62ee
https://blog.csdn.net/zwq912318834/article/details/77689568