MongoDB 及 PyMongo 的基本用法

Dom_秋發表於2019-03-27

本文介紹瞭如何使用 MongoDB 的 CURD, 及使用 PyMongo進行相應操作, 是一篇掃盲貼.

1. 安裝與執行

Mac
# 安裝
brew tap mongodb/brew
brew install mongodb-community@4.0

# 啟動
brew services start mongodb-community@4.0

# 日誌檔案
/usr/local/var/log/mongodb/mongo.log

# 配置檔案
/usr/local/etc/mongod.conf
複製程式碼
Linux(ubuntu)
# 安裝
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org

# 啟動/停止/重啟
sudo service mongod start
sudo service mongod stop
sudo service mongod restart

# 日誌檔案
/var/log/mongodb/mongod.log

# 配置檔案
/etc/mongod.conf
複製程式碼
Windows
學技術還是用Linux吧, 虛擬機器裝ubuntu.
mongodb 不支援 WSL.
複製程式碼

2. 概念

在使用mongodb前我們先理一下概念, 與關係型資料庫不同, mongodb是非關係型文件資料庫. 它沒有外來鍵的說法, 儲存的是 BSON(類似JSON的資料結構).

從pymongo拿來的示意圖很好的解釋了它的資料結構.

MongoDB 及 PyMongo 的基本用法

與關係型資料庫的概念對比

關係型概念 MongoDB 等價概念
Database Database
Tables Collections
Rows Documents
Index Index

最大的區別是我們不再受表結構的限制, 可以寫入各種json. 反正我們操作的就是一條記錄麻, 不管一條條row, 還是一個個json document(這是一把雙刃劍).

3. Mongo Shell

我們可以進入 mongo shell 操作 mongodb. 也可以另行下載帶介面的客戶端, 但自帶的工具已經夠用.

進入 mongo shell, 列出db, collections.

$ mongo
> show databases 
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB

> use test # 使用指定db
switched to db test

> db # 顯示當前db
test

> show collections # 列出當前db下的collection
複製程式碼

mongo的db和collection不需要顯式 create, 它們會在你插入時自動生成.

> use demo # 切換db, 切換db即建立
> db.inventory.insert({first_doc: "This is my first doc."})
WriteResult({ "nInserted" : 1 })

> show dbs # 這個demo db會在插入資料時自動建立
...
demo
...

> show collections # 這個collection會在插入資料時自動建立
inventory

> db.inventory.find({})
{ "_id" : ObjectId("5c9ad59a52fc8581a5707ce9"), "first_doc" : "This is my first doc." }

> db.inventory.drop() # 刪除collection
> db.dropDatabase() # 刪除db
複製程式碼
insert

命令:

db.collection.insertOne() # 插入一條collection
db.collection.insertMany() # 插入多條
db.collection.insert() # 插入一或多條
複製程式碼

舉例:

db.inventory.insertOne(
   { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)

db.inventory.insertMany([
   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])

db.inventory.insert([
   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
複製程式碼
query

命令:

db.collection.findOne() # 查詢一條
db.collection.findMany() # 查詢多條
db.collection.find() # 查詢一或多條
複製程式碼

舉例

db.inventory.find({}) # 相當於select * from inventory;

db.inventory.find({status: "D"})
# select * from inventory where status = 'D';

db.inventory.find({status: {$in: ["A", "D"]}})
# select * from inventory where status in ("A", "D");

db.inventory.find({status: "A", qty: {$lt: 30}})
# select * from inventory where status = 'A' and qty < 30;

db.inventory.find({$or: [{status: "A"}, {qty: {$lt: 30}}]})
# select * from inventory whre status = 'A' or qty < 30;

db.inventory.find({status: "A", $or: [{qty: {$lt: 30}}, {item: /^p/}]})
# select * from inventory where status = 'A' AND (qty < 30 OR item like 'p%');
複製程式碼

操作符

: # =
$lt # <
$lte # <=
$gt # >
$gte # >=
$in # in
$or # or
{}, {} # ,是and
複製程式碼
update

命令:

db.collection.updateOne() # 更新一條
db.collection.updateMany() # 更新多條
db.collection.replaceOne() # 替換一條
複製程式碼

舉例

db.inventory.updateOne(
   { item: "journal" },
   {
     $set: { "size.uom": "in", status: "P" },
     $currentDate: { lastModified: true }
   }
)
# update inventory set size.uom='cm', status='P', 
# lastModified=NOW() where id in (
#    select id from (
#        select id from inventory where item ='paper' limit 1
#    ) tmp
# );
# 為了讓等價sql的正確性, 不得不寫很長.
# 實際這裡就是隻修改一條記錄的意思.

db.inventory.updateMany(
   { "qty": {$lt: 30}},
   {
     $set: { "size.uom": "cm", status: "A" },
     $currentDate: { lastModified: true }
   }
)
# 修改所有 qty < 30 的記錄.

db.inventory.replaceOne(
   { item: "mat" },
   { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)
# 匹配 item = mat 的一條記錄替換為後面的 {item: ...}
複製程式碼

操作符

$set # update set x = n
$inc # update set x = x + n
複製程式碼
delete

命令:

db.collection.deleteOne() # 刪除一條
db.collection.deleteMany() # 刪除一條
複製程式碼

舉例

db.inventory.deleteOne({status:"A"}) # 匹配條件,刪一條
db.inventory.deleteMany({status:"A"}) # 刪除所有匹配條件的記錄
db.inventory.deleteMany({}) # 全刪所有inventory下的document
複製程式碼
aggregate pipeline

聚合管道, 意思就是把多個聚合操作一步步執行.

db.inventory.aggregate([
    {$match: {status: "A"}},
    {$group: {_id: "$item", total: {$sum: "$qty"}}}
])

# select sum('qty') as total, item as _id from inventory 
# where status = 'A' group by item;

{ "_id" : "notebook", "total" : 50 }
{ "_id" : "postcard", "total" : 45 }
{ "_id" : "journal", "total" : 25 }

複製程式碼

4. PyMongo

PyMongo是官網庫, 熟悉完 mongo 的原生命令, 使用pymongo就是類推.

install
pip install pymongo
複製程式碼
client
from pymongo import MongoClient

client = MongoClient()
db = client.test # 這裡用回測試的db

# 測試一下, 把之前插入的資料全部輸出
result = db.inventory.find({})
for d in result:
    print(d)

複製程式碼
insert
names = ['JD','Ali','Ten', 'Bd', 'YZ']
company_area = ['Shengzhen', 'BeiJing', 'Shanghai', 'Hangzhou']
company_department = ['BD','Dev','Opt', 'UI', 'PM', 'QA']
company_worktime = ['996', '9116', '885', '997', '975']
docs = []
for x in range(1, 101):
    doc = {
        'name' : names[randint(0, (len(names)-1))],
        'area': company_area[randint(0, (len(company_area)-1))],
        'department': company_department[randint(0, (len(company_department)-1))],
        'total' : randint(1, 10),
        'worktime' : company_worktime[randint(0, (len(company_worktime)-1))] 
    }
    docs.append(doc)
db.reviews.insert_many(docs)
複製程式碼

MongoDB 及 PyMongo 的基本用法

query
# 聚合查詢並按公司名, 部門排序

ret = db.reviews.aggregate([
    {'$group': {'_id': {'name':'$name', 'department': '$department'}, 'count': {'$sum': '$total'}}}, 
    {'$sort': {'_id.name': -1, '_id.department': -1}}
])

for r in ret:
    print(r)
複製程式碼

MongoDB 及 PyMongo 的基本用法

update
db.reviews.update_many({'name': 'Ali', 'area':'Hangzhou', 'department':'QA'}, 
{'$inc': {'total': 1}
})

result = db.reviews.find({'name': 'Ali', 'area':'Hangzhou', 'department':'QA'})
for r in result:
    print(r)
複製程式碼
delete
db.reviews.delete_many({'name': 'Ali', 'area':'Hangzhou', 'department':'QA'})

result = db.reviews.find({'name': 'Ali', 'area':'Hangzhou', 'department':'QA'})
for r in result:
    print(r)

複製程式碼

pymongo 的用法跟 mondo shell 幾乎是一致的, 稍微轉換一下能用.

相關文章