一、安裝
pip3 install pymongo
二、基本使用
1. 導(dǎo)入模塊
import pymongo
2. 建立本地鏈接
cl = pymongo.MongoClient('localhost', 27017)
# 或者
cl = Mongocl('mongodb://localhost:27017/')
3. 獲取數(shù)據(jù)庫
一個MongoDB實例可以支持多個獨(dú)立的 數(shù)據(jù)庫。在使用PyMongo時,您可以使用Mongocl實例上的屬性樣式訪問來訪問數(shù)據(jù)庫:
# 查看當(dāng)前都有那些庫
cl.database_names()
# 獲取數(shù)據(jù)庫對象
db = cl.test_database
或者
db = cl['test_database']
4. 獲取集合
一個集合是一組存儲在MongoDB中的文檔,并且可以被認(rèn)為是大致在關(guān)系數(shù)據(jù)庫中的表。
在 PyMongo 中獲取集合與獲取數(shù)據(jù)庫的工作方式相同:
# 查看當(dāng)前庫中都有那些集合
db.collection_names()
# 獲取集合對象
collection = db.test_collection
# 或者
collection = db['test-collection']
合法的集合名:
- 集合名不能是空字符串""。
- 集合名不能含有\(zhòng)0字符(空字符),這個字符表示集合名的結(jié)尾。
- 集合名不能以"system."開頭,這是為系統(tǒng)集合保留的前綴。
- 用戶創(chuàng)建的集合名字不能含有保留字符。有些驅(qū)動程序的確支持在集合名里面包含,這是因為某些系統(tǒng)生成的集合中包含該字符。除非你要訪問這種系統(tǒng)創(chuàng)建的集合,否則千萬不要在名字里出現(xiàn)$。
三、惰性機(jī)制
關(guān)于MongoDB中的集合(和數(shù)據(jù)庫)的一個重要注意事項是它們是懶惰地創(chuàng)建的。
上述命令都沒有在MongoDB服務(wù)器上實際執(zhí)行過任何操作。集合和數(shù)據(jù)庫在第一個文檔被插入時創(chuàng)建。
四、 文檔
MongoDB中的數(shù)據(jù)使用JSON樣式的文檔來表示(并存儲)。
在PyMongo中,我們使用字典來表示 Mongo 中文檔。例如,以下字典可能用于表示博客文章:
In [34]: import datetime
In [35]: post = {"author": "yangge",
"text": "云計算-NoSQL",
"tags": ["mongodb", "python", "pymongo"],
"date": datetime.datetime.now()}
請注意,文檔可以包含本機(jī)Python類型(如datetime.datetime實例),這些類型 將自動轉(zhuǎn)換為適當(dāng)?shù)腂SON類型并從其中轉(zhuǎn)換
文檔特點(diǎn):
- 文檔中的鍵/值對是有序的。
- 文檔中的值不僅可以是在雙引號里面的字符串,還可以是其他幾種數(shù)據(jù)類型(甚至可以是整個嵌入的文檔)。
- MongoDB區(qū)分類型和大小寫。
- MongoDB的文檔不能有重復(fù)的鍵。
- 文檔的鍵是字符串。除了少數(shù)例外情況,鍵可以使用任意UTF-8字符。
文檔鍵命名規(guī)范:
- 鍵不能含有\(zhòng)0 (空字符)。這個字符用來表示鍵的結(jié)尾。
- .和$有特別的意義,只有在特定環(huán)境下才能使用。
- 以下劃線"_"開頭的鍵是保留的(不是嚴(yán)格要求的)。
五、 插入文件數(shù)據(jù)
# 使用、創(chuàng)建了 posts 集合
In [36]: posts_col = db.posts
# 向 psts 集合中插入一個文檔,并返回了 _id 對象
In [37]: post_id = posts_col.insert_one(post).inserted_id
In [38]: post_id
Out[38]: ObjectId('5a9f8eb2e138232b02854093')
In [41]: print(post_id)
5a9f8eb2e138232b02854093
In [42]: post_id.__str__()
Out[42]: '5a9f8eb2e138232b02854093'
驗證
插入第一個文檔后,posts集合實際上已經(jīng)在服務(wù)器上創(chuàng)建。
我們可以通過列出數(shù)據(jù)庫中的所有集合來驗證這一點(diǎn):
In [45]: db.collection_names(include_system_collections=False)
Out[45]: ['posts_col']
六、 使用find_one()獲取單個文檔
可以在MongoDB中執(zhí)行的最基本的查詢類型是 find_one()。
此方法返回與查詢匹配的單個文檔(如果沒有匹配,則返回None)。
當(dāng)您知道只有一個匹配的文檔,或者只對第一個匹配感興趣時,它非常有用。
這里我們使用 find_one()從posts集合中獲取第一個文檔:
In [47]: posts_col.find_one()
Out[47]:
{'_id': ObjectId('5a9f8a6de138232b02854092'),
'author': 'Mike',
'date': datetime.datetime(2018, 3, 7, 6, 44, 54, 672000),
'tags': ['mongodb', 'python', 'pymongo'],
'text': 'My first blog post!'}
指定匹配查詢
In [47]: posts_col.find_one(post)
Out[47]:
{'_id': ObjectId('5a9f8eb2e138232b02854093'),
'author': 'yangge',
'date': datetime.datetime(2018, 3, 7, 15, 1, 0, 355000),
'tags': ['mongodb', 'python', 'pymongo'],
'text': '云計算-NoSQL'}
# --------------------------------------------------
In [88]: posts_col.find_one({'author': 'yangge'})
Out[88]:
{'_id': ObjectId('5a9f8eb2e138232b02854093'),
'author': 'yangge',
'date': datetime.datetime(2018, 3, 7, 15, 1, 0, 355000),
'tags': ['mongodb', 'python', 'pymongo'],
'text': '云計算-NoSQL'}
最好通過 _id_obj 查找
假如你創(chuàng)建了同樣的數(shù)據(jù)在 Mongo 里,他會同時存在,但是 _id 不一樣。
所以建議使用創(chuàng)建數(shù)據(jù)時返回的 _id 對象來查詢。
In [93]: posts_col.insert_one({"shark": "鯊魚"}).inserted_id
Out[93]: ObjectId('5a9f97d1e138232b02854094')
In [94]: posts_col.insert_one({"shark": "鯊魚"})
Out[94]: <pymongo.results.InsertOneResult at 0x7f74d652e388>
In [95]: shark_id = posts_col.insert_one({"shark": "鯊魚", "age": "18"}).inserted_id
In [96]: shark_id_obj = posts_col.insert_one({"shark": "鯊魚"}).inserted_id
In [97]: posts_col.find_one({"_id": shark_id_obj})
Out[97]: {'_id': ObjectId('5a9f9807e138232b02854097'), 'shark': '鯊魚'}
In [98]: posts_col.find_one({"_id": shark_id})
Out[98]: {'_id': ObjectId('5a9f97fae138232b02854096'), 'shark': '鯊魚'}
# 注意有個空格哦
In [99]: posts_col.find_one({"shark": " 鯊魚"})
In [100]: posts_col.find_one({"shark": "鯊魚"})
Out[100]: {'_id': ObjectId('5a9f97d1e138232b02854094'), 'shark': '鯊魚'}
從字符串轉(zhuǎn)換為ObjectId
In [121]: from bson.objectid import ObjectId
In [122]: posts_col.find_one({'_id': ObjectId(shark_id_obj)})
Out[122]: {'_id': ObjectId('5a9f9807e138232b02854097'), 'shark': '鯊魚'}
==在 Python2 中==
MongoDB以BSON格式存儲數(shù)據(jù)。BSON字符串是UTF-8編碼的,所以PyMongo必須確保它存儲的任何字符串只包含有效的UTF-8數(shù)據(jù)。常規(guī)字符串(<type'str'>)被驗證并保存不變。Unicode字符串(<type'unicode'>)首先被編碼為UTF-8。我們的示例字符串在Python shell中被表示為u'Mike'而不是'Mike',原因是PyMongo將每個BSON字符串解碼為Python unicode字符串,而不是常規(guī)str。
關(guān)于 _id
In [110]: shark_id.generation_time.isoformat()
Out[110]: '2018-03-07T07:42:50+00:00'
七、 批量插入
為了讓查詢更有趣,讓我們插入更多的文檔。除了插入單個文檔外,我們還可以通過將列表作為第一個參數(shù)傳遞給insert_many()來執(zhí)行批量插入操作。這會將每個文檔插入列表中,只向服務(wù)器發(fā)送一條命令:
簡單粗暴的上官方示例
>>> new_posts = [{"author": "Mike",
... "text": "Another post!",
... "tags": ["bulk", "insert"],
... "date": datetime.datetime(2009, 11, 12, 11, 14)},
... {"author": "Eliot",
... "title": "MongoDB is fun",
... "text": "and pretty easy too!",
... "date": datetime.datetime(2009, 11, 10, 10, 45)}]
>>> result = posts_col.insert_many(new_posts)
>>> result.inserted_ids
[ObjectId('...'), ObjectId('...')]
查詢多個文檔
我們使用find() 方法來獲取多個文檔 。
find() 返回一個 Cursor實例,它允許我們遍歷所有匹配的文檔。
例如,我們可以迭代posts集合中的每個文檔:
In [129]: for post in posts_col.find():
...: print(post)
...:
{'_id': ObjectId('5a9f8a6de138232b02854092'), 'author': 'Mike', 'text': 'My first blog post!', 'tags': ['mongodb', 'python', 'pymongo'], 'date': datetime.datetime(2018, 3, 7, 6, 44, 54, 672000)}
{'_id': ObjectId('5a9f8eb2e138232b02854093'), 'author': 'yangge', 'text': '云計算-NoSQL', 'tags': ['mongodb', 'python', 'pymongo'], 'date': datetime.datetime(2018, 3, 7, 15, 1, 0, 355000)}
{'_id': ObjectId('5a9f97d1e138232b02854094'), 'shark': '鯊魚'}
{'_id': ObjectId('5a9f97e1e138232b02854095'), 'shark': '鯊魚'}
{'_id': ObjectId('5a9f97fae138232b02854096'), 'shark': '鯊魚'}
{'_id': ObjectId('5a9f9807e138232b02854097'), 'shark': '鯊魚'}
{'_id': ObjectId('5a9f9e48e138232b02854098'), 'author': 'Mike', 'text': 'Another post!', 'tags': ['bulk', 'insert'], 'date': datetime.datetime(2009, 11, 12, 11, 14)}
{'_id': ObjectId('5a9f9e48e138232b02854099'), 'author': 'Eliot', 'title': 'MongoDB is fun', 'text': 'and pretty easy too!', 'date': datetime.datetime(2009, 11, 10, 10, 45)}
就像我們用 find_one()所做的那樣,我們可以傳遞一個文檔給 find() 來限制返回的結(jié)果。
在這里,我們只得到那些作者是 "鯊魚" 的文檔:
In [133]: for post in posts_col.find({"shark": '鯊魚'}):
...: print(post)
...:
{'_id': ObjectId('5a9f97d1e138232b02854094'), 'shark': '鯊魚'}
{'_id': ObjectId('5a9f97e1e138232b02854095'), 'shark': '鯊魚'}
{'_id': ObjectId('5a9f97fae138232b02854096'), 'shark': '鯊魚'}
{'_id': ObjectId('5a9f9807e138232b02854097'), 'shark': '鯊魚'}
計數(shù)
In [134]: posts_col.count()
Out[134]: 8
In [135]: posts_col.find({"author": "yangge"}).count()
Out[135]: 1
范圍查詢
MongoDB支持許多不同類型的高級查詢。例如,讓我們執(zhí)行查詢,將結(jié)果限制為比特定日期更早的帖子,還可以按作者對結(jié)果進(jìn)行排序
In [136]: d = datetime.datetime(2018, 11, 12, 12)
In [137]: for post in posts_col.find({"date": {"$lt": d}}).sort("author"):
...: print(post)
...:
{'_id': ObjectId('5a9f9e48e138232b02854099'), 'author': 'Eliot', 'title': 'MongoDB is fun', 'text': 'and pretty easy too!', 'date': datetime.datetime(2009, 11, 10, 10, 45)}
{'_id': ObjectId('5a9f8a6de138232b02854092'), 'author': 'Mike', 'text': 'My first blog post!', 'tags': ['mongodb', 'python', 'pymongo'], 'date': datetime.datetime(2018, 3, 7, 6, 44, 54, 672000)}
{'_id': ObjectId('5a9f9e48e138232b02854098'), 'author': 'Mike', 'text': 'Another post!', 'tags': ['bulk', 'insert'], 'date': datetime.datetime(2009, 11, 12, 11, 14)}
{'_id': ObjectId('5a9f8eb2e138232b02854093'), 'author': 'yangge', 'text': '云計算-NoSQL', 'tags': ['mongodb', 'python', 'pymongo'], 'date': datetime.datetime(2018, 3, 7, 15, 1, 0, 355000)}
排序
db.mycollection
mycol = db.mycollection
mycol.insert_one({'name': '姜文'})
result_dic = db.mycollection.find().sort("age")
for item in result_dic:
print(item)
更新
更新數(shù)據(jù)庫, ObjectId 需要引入
from bson.objectid import ObjectId
db.mycollection.update({'_id': ObjectId('59255118d92fac43dcb1999a')}, {'$set': {'name': '九筒'}})
刪除
刪除指定數(shù)據(jù)
db.mycollection.remove({'name':'王二麻33333'})
刪除全部數(shù)據(jù)(慎用)
db.mycollection.remove()
### capped collections (擴(kuò)展)
Capped collections 就是固定大小的collection。
它有很高的性能以及隊列過期的特性(過期按照插入的順序). 有點(diǎn)和 "RRD" 概念類似。
Capped collections是高性能自動的維護(hù)對象的插入順序。它非常適合類似記錄日志的功能 和標(biāo)準(zhǔn)的collection不同,你必須要顯式的創(chuàng)建一個capped collection, 指定一個collection的大小,單位是字節(jié)。collection的數(shù)據(jù)存儲空間值提前分配的。
要注意的是指定的存儲大小包含了數(shù)據(jù)庫的頭信息。
db.createCollection("mycoll", {capped:true, size:100000})
- 在capped collection中,你能添加新的對象。
- 能進(jìn)行更新,然而,對象不會增加存儲空間。如果增加,更新就會失敗 。
- 數(shù)據(jù)庫不允許進(jìn)行刪除。使用drop()方法刪除collection所有的行。
- 注意: 刪除之后,你必須顯式的重新創(chuàng)建這個collection。
- 在32bit機(jī)器中,capped collection最大存儲為1e9( 1X109)個字節(jié)。
元數(shù)據(jù)
數(shù)據(jù)庫的信息是存儲在集合中。它們使用了系統(tǒng)的命名空間:
dbname.system.*
在MongoDB數(shù)據(jù)庫中名字空間 <dbname>.system.* 是包含多種系統(tǒng)信息的特殊集合(Collection),如下:
| 集合命名空間 | 描述 |
|---|---|
| dbname.system.namespaces | 列出所有名字空間。 |
| dbname.system.indexes | 列出所有索引。 |
| dbname.system.profile | 包含數(shù)據(jù)庫概要(profile)信息。 |
| dbname.system.users | 列出所有可訪問數(shù)據(jù)庫的用戶。 |
| dbname.local.sources | 包含復(fù)制對端(slave)的服務(wù)器信息和狀態(tài)。 |
對于修改系統(tǒng)集合中的對象有如下限制。
在
{{system.indexes}}插入數(shù)據(jù),可以創(chuàng)建索引。但除此之外該表信息是不可變的(特殊的
drop index命令將自動更新相關(guān)信息)。{{system.users}}是可修改的。{{system.profile}}是可刪除的。
MongoDB 數(shù)據(jù)類型
下表為MongoDB中常用的幾種數(shù)據(jù)類型。
| 數(shù)據(jù)類型 | 描述 |
|---|---|
| String | 字符串。存儲數(shù)據(jù)常用的數(shù)據(jù)類型。在 MongoDB 中,UTF-8 編碼的字符串才是合法的。 |
| Integer | 整型數(shù)值。用于存儲數(shù)值。根據(jù)你所采用的服務(wù)器,可分為 32 位或 64 位。 |
| Boolean | 布爾值。用于存儲布爾值(真/假)。 |
| Double | 雙精度浮點(diǎn)值。用于存儲浮點(diǎn)值。 |
| Min/Max keys | 將一個值與 BSON(二進(jìn)制的 JSON)元素的最低值和最高值相對比。 |
| Array | 用于將數(shù)組或列表或多個值存儲為一個鍵。 |
| Timestamp | 時間戳。記錄文檔修改或添加的具體時間。 |
| Object | 用于內(nèi)嵌文檔。 |
| Null | 用于創(chuàng)建空值。 |
| Symbol | 符號。該數(shù)據(jù)類型基本上等同于字符串類型,但不同的是,它一般用于采用特殊符號類型的語言。 |
| Date | 日期時間。用 UNIX 時間格式來存儲當(dāng)前日期或時間。你可以指定自己的日期時間:創(chuàng)建 Date 對象,傳入年月日信息。 |
| Object ID | 對象 ID。用于創(chuàng)建文檔的 ID。 |
| Binary Data | 二進(jìn)制數(shù)據(jù)。用于存儲二進(jìn)制數(shù)據(jù)。 |
| Code | 代碼類型。用于在文檔中存儲 JavaScript 代碼。 |
| Regular expression | 正則表達(dá)式類型。用于存儲正則表達(dá)式。 |