本文介紹瞭如何使用
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 等價概念 |
---|---|
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)
複製程式碼
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)
複製程式碼
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 幾乎是一致的, 稍微轉換一下能用.