文章首發:點點寒彬的博客
前言
都說MongoDB這個NoSql數據庫特別友好,使用起來也非常方便,今天稍微接觸了一下,發現真的是非常非常簡單,但是網上對這塊內容涉及的很少,而且很多內容都是很老的版本使用的方法,我看了一下官方API文檔中描述的內容也不多,順手翻譯一下吧,造福一下后來人。
注:我并不是逐字逐句的翻譯,在某些地方我無法精確翻譯的時候,我概括了大概的意思,有能力的可以直接看官方文檔
前提條件
首先,我們需要安裝PyMongo模塊,在PythonShell中下面的代碼能正常運行且無報錯。
>>> import pymongo
當然,你的MongoDB需要在默認地址和端口開啟,你可以按照這個方法確認你是否安裝了MongoDB:
$ mongod
建立一個MongoClient
第一步我們需要建立一個MongoClient來運行MongoDB,這個做起來非常簡單:
>>> from pymongo import MongoClient
>>> client = MongoClient()
上面的代碼會連接默認的地址和端口,我們也可以自己指定地址和端口,像下面這樣:
>>> client = MongoClient('localhost', 27017)
或者使用MongoDB的URI連接:
>>> client = MongoClient('mongodb://localhost:27017/')
獲取數據庫
一個MongoDB可以提供多個數據庫接口。當使用PyMongo的時候,你可以使用獲取屬性的方式建立MongoClient:
>>> db = client.test_database
如果你使用上面的方法無法獲取數據庫的時候,你可以使用字典的方式來獲取數據庫。
獲取連接
獲取連接的方式和獲取數據庫的方式一樣,也可以使用獲取屬性的方式:
>>> collection = db.test_collection
或者使用字典的方式:
>>> collection = db['test-collection']
注意:使用MongoDB建立連接非常容易,但是上面的所有操作都不是實實在在的操作了MongoDB,當第一次獲取數據庫和建立連接的時候,數據庫和連接會被創建。
文檔
MongoDB的數據格式存儲使用的是JSON風格,在PyMongo中,我們使用的字典類型就相當于數據。比如下面的數據就類似博客中的post信息:
>>> import datetime
>>> post = {"author": "Mike",
... "text": "My first blog post!",
... "tags": ["mongodb", "python", "pymongo"],
... "date": datetime.datetime.utcnow()}
數據格式可以容納python的類型(就像datetime.datetime)
插入數據
往數據庫插入一條數據我們使用insert_one()方法:
>>> posts = db.posts
>>> post_id = posts.insert_one(post).inserted_id
>>> post_id
ObjectId('...')
當我們插入數據成功的時候,MongoDB會生成一個特殊的主鍵“_id”。這個主鍵“_id”的值是唯一的。insert_one()返回的值就是這個主鍵的值。
插入第一條數據后,數據庫、數據表和連接都建立了,我們可以查看列表中的所有信息:
>>> db.collection_names(include_system_collections=False)
[u'posts']
使用find_one()方法獲取一條記錄
在MongoDB中最基本的方法就是find_one()。這個方法返回一條符合條件的記錄(或者None)。當你知道某條信息只有一個的時候,這個方法非常有用,或者返回第一條數據,這里我們使用這個方法獲取第一條數據:
>>> posts.find_one()
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike'
結果是我們之前插入的一條字典型的數據。
注意:返回結果中的“_id”是插入數據時自動添加的。
find_one()同時也提供了精確查找的功能,下面的示例是我們定位author為Mike的代碼:
>>> posts.find_one({"author": "Mike"})
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike'
如果我們把author換成另外一個,則不會返回結果:
>>> posts.find_one({"author": "Eliot"})
>>>
使用ObjectId查詢
我們也可以用“_id”來查詢,下面是我們的示例:
>>> post_id
ObjectId(...)
>>> posts.find_one({"_id": post_id})
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike'
注意:ObjectId和轉換為字符串的ObjectId是不一樣的:
>>> post_id_as_str = str(post_id)
>>> posts.find_one({"_id": post_id_as_str}) # No result
>>>
在web應用中一個很常見的現象就是從URI中獲取ObjectId來查詢后臺記錄。在使用這個之前需要把str類型轉換成ObjectId類型:
from bson.objectid import ObjectId
# The web framework gets post_id from the URL and passes it as a string
def get(post_id):
# Convert from string to ObjectId:
document = client.db.collection.find_one({'_id': ObjectId(post_id)})
Unicode Strings注意事項
你可能會注意到我們的數據和存進去的數據有一些不一樣,比如( u’Mike’ 而不是‘Mike’)。
MongoDB是使用BSON來存儲數據。BSON是使用utf-8來編碼的。所以PyMongo存儲的str類型必須是utf-8的。(‘str’類型)也是要被支持的,因此Unicode類型(<‘unicode’類型>)需要先編碼成utf-8,我們的示例中PythonShell顯示的是u’Mike’而不是‘Mike’就是因為PyMongo解碼了BSON的string變成Python的unicode string。
大量的插入數據
為了讓查詢更有意思,我們需要插入多一些數據。能夠新增一條記錄,我們也可以做到新增多條記錄。使用insert_many()方法插入由第一條數據組成的列表,只需要往服務端發送一條命令:
>>> 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.insert_many(new_posts)
>>> result.inserted_ids
[ObjectId('...'), ObjectId('...')]
這個例子有幾個有意思的地方:
- insert_many()返回了兩個相互對應ObjectId
- new_post[1]有一個不同的地方,多了一個“tags”字段。而現在我們又多了一個字段,這就是我們說MongoDB非常schema-free(開放?)
查詢一條以上的記錄
我們使用find()方法來獲取一條以上的記錄。find()返回一組符合條件的記錄,并且允許我們通過迭代的方式獲取它們。例如,在post中我們可以迭代的獲取所有查詢的數據:
>>> for post in posts.find():
... post
...
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}
{u'date': datetime.datetime(2009, 11, 10, 10, 45), u'text': u'and pretty easy too!', u'_id': ObjectId('...'), u'author': u'Eliot', u'title': u'MongoDB is fun'}
就像我們使用find_one()一樣,我們也可以在這里加上查詢條件來獲取符合條件的數據:
>>> for post in posts.find({"author": "Mike"}):
... post
...
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}
計數
如果我們只想獲取數量,我們可以使用count()方法來代替全記錄查詢。我們可以獲得查詢的數量:
>>> posts.count()
3
或者獲得符合條件的數量:
>>> posts.find({"author": "Mike"}).count()
2
不同種類的查詢
MongoDB還提供了許多種類的查詢方式。例如我們查詢數據的日期小于某一個日期,且按照author字段來排序:
>>> d = datetime.datetime(2009, 11, 12, 12)
>>> for post in posts.find({"date": {"$lt": d}}).sort("author"):
... print post
...
{u'date': datetime.datetime(2009, 11, 10, 10, 45), u'text': u'and pretty easy too!', u'_id': ObjectId('...'), u'author': u'Eliot', u'title': u'MongoDB is fun'}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}
這里我們使用“$lt”來做一個限制的查詢,使用sort()來對author字段排序。
主鍵
增加一個主鍵能夠幫助我們快速而準確的查詢記錄,也可以使我們存儲的數據更加有用。在這個示例中,我們將會展示在一個已存在主鍵的表中新增一個主鍵:
首先,我們要新增一個主鍵:
>>> result = db.profiles.create_index([('user_id', pymongo.ASCENDING)],
... unique=True)
>>> list(db.profiles.index_information())
[u'user_id_1', u'_id_']
注意,我們現在有兩個主鍵了,一個是MongoDB自帶的”_id“,另一個是我們新增的”user_id“。
現在,我們來新增一些用戶信息:
>>> user_profiles = [
... {'user_id': 211, 'name': 'Luke'},
... {'user_id': 212, 'name': 'Ziltoid'}]
>>> result = db.profiles.insert_many(user_profiles)
我們新增的主鍵阻止我們新增一條已存在這個主鍵的記錄。
>>> new_profile = {'user_id': 213, 'name': 'Drew'}
>>> duplicate_profile = {'user_id': 212, 'name': 'Tommy'}
>>> result = db.profiles.insert_one(new_profile) # This is fine.
>>> result = db.profiles.insert_one(duplicate_profile)
Traceback (most recent call last):
pymongo.errors.DuplicateKeyError: E11000 duplicate key error index: test_database.profiles.$user_id_1 dup key: { : 212 }
寫在最后
官方文檔上并沒有給出刪除,修改記錄的方法,或許是我目前還沒看到吧,等看到了我會再補充上來的。文檔比較短,翻譯的過程中由于本人英語水平有限,并不能做到逐字逐句的翻譯,也無法保證完全準確,并且會有一些地方的內容念起來并不是那么的順口,但是官方文檔想表達的大概意思應該是不會錯的。