1. 程式人生 > >python使用MongoDB,備忘

python使用MongoDB,備忘

知識備份,內容多來自知乎的Jerry專欄

安裝pymongo

pymongo是由MongoDB開發者釋出的官方驅動程式,官方文件在這裡
安裝:

pip install pymongo

在命令列中import pymongo沒有異常則安裝成功。

建立連線

使用MongoClient物件建立連線:

from pymongo import MongoClient
client = MongoClient()

上面的程式碼,將預設建立連線到主機(localhost)和埠(27017)。也可以指定主機或埠:

client = MongoClient('localhost', 27017)

或者使用MongoURI格式:

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

訪問資料庫

一旦你有一個連結的MongoClient例項,你可以在Mongo伺服器中訪問任何資料庫。可以把一個數據庫當做一個屬性一樣訪問:

db = client.meinvxiezhenji

或者也可以使用字典的形式訪問:

db = client['meinvxiezhenji']

如果你的指定資料庫還沒有建立,也沒有關係。通過指定此資料庫名稱並將資料儲存到其中,MongoDB將自動為你建立資料庫。

插入文件

在資料庫中儲存資料非常簡單,前面已經建立了meinvxiezhenji的連線,這裡只需要指定要使用其中的哪個集合就可以了。在MongoDB中,一個集合是在資料庫中儲存在一起的一組文件(類似於SQL的表)。集合和文件像是SQL的表和行。選擇集合後,使用insert_one()方法插入文件到集合中:

posts = db.mzitu
post_data = {
    'title': 'Python and MongoDB',
    'content': 'PyMongo is fun, you guys',
    'author': 'who's here'
}
result = posts.insert_one(post_data)
print('One post: {0}'.format(result.inserted_id))

我們甚至可以插入很多文件,使用方法insert_many()。此方法接受一個list引數:

post_1 = {
    'title'
: 'Python and MongoDB', 'content': 'PyMongo is fun, you guys', 'author': 'Scott' } post_2 = { 'title': 'Virtual Environments', 'content': 'Use virtual environments, you guys', 'author': 'Scott' } post_3 = { 'title': 'Learning Python', 'content': 'Learn Python, it is easy', 'author': 'Bill' } new_result = posts.insert_many([post_1, post_2, post_3]) print('Multiple posts: {0}'.format(new_result.inserted_ids))

你應該看到類似輸出:

One post: 584d947dea542a13e9ec7ae6
Multiple posts: [
    ObjectId('584d947dea542a13e9ec7ae7'),
    ObjectId('584d947dea542a13e9ec7ae8'),
    ObjectId('584d947dea542a13e9ec7ae9')
]

注意: 不要擔心,你和上面顯示不一樣。它們是在插入資料時,由Unix的紀元,機器識別符號和其他唯一資料組成的動態標識。

檢索文件

檢索文件可以使用find_one()方法,比如要找到author為Pete的記錄:

petes_post = posts.find_one({'author': 'Pete'})
print(petes_post)

執行結果:

{
    'author': 'Bill', 'title': 'Learning Python',
    'content': 'Learn Python, it is easy',
    '_id': ObjectId('584c4afdea542a766d254241')
}

您可能已經注意到,這篇文章的ObjectId是設定的_id,這是以後可以使用唯一標識。如果需要查詢多條記錄可以使用find()方法:

scotts_posts = posts.find({'author': 'Scott'})
print(scotts_posts)

結果:

<pymongo.cursor.Cursor object at 0x109852f98>

他的主要區別在於文件資料不是作為陣列直接返回給我們。相反,我們得到一個遊標物件的例項。這Cursor是一個包含相當多的輔助方法,以幫助您處理資料的迭代物件。要獲得每個文件,只需遍歷結果:

for post in scotts_posts:
    print(post)

MongoEngine

雖然PyMongo是非常容易使用,總體上是一個偉大的輪子,但是許多專案使用它都可能太低水平。簡而言之,你必須編寫很多自己的程式碼來持續地儲存,檢索和刪除物件。PyMongo之上提供了一個更高的抽象一個庫是MongoEngine。

MongoEngine是一個物件文件對映器(ODM),它大致相當於一個基於SQL的物件關係對映器(ORM,把表結構對映到物件上,python中比較有名的SQLAlchemy和這個用法挺像的)。MongoEngine提供的抽象是基於類的,所以你建立的所有模型都是類。雖然有相當多的Python的庫可以幫助您使用MongoDB,MongoEngine是一個更好的,因為它有一個很好的組合的功能,靈活性和社群支援。

使用pip安裝:

pip install mongoengine==0.10.7

連線:

from mongoengine import *
connect('mongoengine_test', host='localhost', port=27017)

和pymongo不同。MongoEngine需要制定資料庫名稱。

定義文件

建立文件之前,需要定義文件中要存放資料的欄位。與許多其他ORM類似,我們將通過繼承Document類,並提供我們想要的資料型別來做到這一點:

import datetime

class Post(Document):
    title = StringField(required=True, max_length=200)
    content = StringField(required=True)
    author = StringField(required=True, max_length=50)
    published = DateTimeField(default=datetime.datetime.now)

在這個簡單的模型中,我們已經告訴MongoEngine,我們的Post例項有title、content、author、published。現在Document物件可以使用該資訊來驗證我們提供它的資料。

因此,如果我們試圖儲存Post的中沒有title那麼它會丟擲一個Exception,讓我們知道。我們甚至可以進一步利用這個並新增更多的限制:

required:設定必須;
default:如果沒有其他值給出使用指定的預設值
unique:確保集合中沒有其他document有此欄位的值相同
choices:確保該欄位的值等於陣列中的給定值之一

儲存文件

將文件儲存到資料庫中,我們將使用save()的方法。如果文件中的資料庫已經存在,則所有的更改將在原子水平上對現有的文件進行。如果它不存在,那麼它會被建立。

這裡是建立和儲存一個文件的例子:

post_1 = Post(
    title='Sample Post',
    content='Some engaging content',
    author='Scott'
)
post_1.save()       # This will perform an insert
print(post_1.title)
post_1.title = 'A Better Post Title'
post_1.save()       # This will perform an atomic edit on "title"
print(post_1.title)

呼叫save()的時候需要注意幾點:

PyMongo將在您呼叫.save()時執行驗證,這意味著它將根據您在類中宣告的模式檢查要儲存的資料,如果違反模式(或約束),則丟擲異常並且不儲存資料;

由於Mongo不支援真正的事務,因此沒有辦法像在SQL資料庫中那樣“回滾”.save()呼叫。

當你儲存的資料沒有title時:

post_2 = Post(content='Content goes here', author='Michael')
post_2.save()

raise ValidationError(message, errors=errors)
mongoengine.errors.ValidationError:
ValidationError (Post:None) (Field is required: ['title'])

面向物件的特性

使用MongoEngine是面向物件的,你也可以新增方法到你的子類文件。例如下面的示例,其中函式用於修改預設查詢集(返回集合的所有物件)。通過使用它,我們可以對類應用預設過濾器,並只獲取所需的物件

class Post(Document):
    title = StringField()
    published = BooleanField()

    @queryset_manager
    def live_posts(clazz, queryset):
        return queryset.filter(published=True)

關聯其他文件

您還可以使用ReferenceField物件來建立從一個文件到另一個文件的引用。MongoEngine在訪問時自動惰性處理引用。

class Author(Document):
    name = StringField()

class Post(Document):
    author = ReferenceField(Author)

Post.objects.first().author.name

在上面的程式碼中,使用文件”外來鍵”,我們可以很容易地找到第一篇文章的作者。其實還有比這裡介紹的更多的欄位類(和引數),所以一定要檢視文件欄位更多資訊。

從所有這些示例中,您應該能夠看到,MongoEngine非常適合管理幾乎任何型別的應用程式的資料庫物件。這些功能使得建立一個高效可擴充套件程式變得非常容易。如果你正在尋找更多關於MongoEngine的幫助,請務必查閱他們的使用者指南。