Document
對象有一個 objects
屬性,用來訪問在數據庫中跟這個類有關的對象。這個 objects
屬性實際上是一個QuerySetManager
,它會建立和返回一個新的 QuerySet
對象的訪問。這個 QuerySet
對象能夠從數據庫中遍歷獲取的文檔:python
# Prints out the names of all the users in the database for user in User.objects: print user.name
能夠經過調用 QuerySet
對象的關鍵字參數來對數據查詢進行過濾,關鍵字查詢中的鍵和你想要查詢的Document
中的字段一致:sql
# This will return a QuerySet that will only iterate over users whose # 'country' field is set to 'uk' uk_users = User.objects(country='uk')
對於內嵌document的字段可使用 __
來代替對象屬性訪問語法中的 .
進行訪問:mongodb
# This will return a QuerySet that will only iterate over pages that have # been written by a user whose 'country' field is set to 'uk' uk_pages = Page.objects(author__country='uk')
在查詢中也可使用操做符,只要將其加在關鍵字的雙下劃線以後便可:數據庫
# Only find users whose age is 18 or less young_users = Users.objects(age__lte=18)
可用的運算符以下:數組
ne
– 不等於≠
服務器
lt
– 小於<
less
lte
– 小於等於≤
nosql
gt
– 大於>
函數
gte
– 大於等於 ≥
post
not
– 否認一個標準的檢查,須要用在其餘操做符以前(e.g. Q(age__not__mod=5)
)
in
– 值在 list
中
nin
– 值不在 list
中
mod
– value % x == y
, 其中 x
和 y
爲給定的值
all
– list
裏面全部的值
size
– 數組的大小
exists
– 存在這個值
如下操做符能夠快捷的進行正則查詢:
exact
– 字符串型字段徹底匹配這個值
iexact
– 字符串型字段徹底匹配這個值(大小寫敏感)
contains
– 字符串字段包含這個值
icontains
– 字符串字段包含這個值(大小寫敏感)
startswith
– 字符串字段由這個值開頭
istartswith
– 字符串字段由這個值開頭(大小寫敏感)
endswith
– 字符串字段由這個值結尾
iendswith
– 字符串字段由這個值結尾(大小寫敏感)
match
– 執行 $elemMatch
操做,因此你可使用一個數組中的 document 實例
PASS
對於大多數字段,這種語法會查詢出那些字段與給出的值相匹配的document,可是當一個字段引用 ListField
的時候,而只會提供一條數據,那麼包含這條數據的就會被匹配上:
class Page(Document): tags = ListField(StringField()) # This will match all pages that have the word 'coding' as an item in the # 'tags' list Page.objects(tags='coding')
你能夠經過 __raw__
參數來使用一個原始的 PyMongo
語句來進行查詢,這樣能夠進行原始的完整查詢:
Page.objects(__raw__={'tags': 'coding'})
就像傳統的ORM同樣,你有時候須要限制返回的結果的數量,或者須要跳過必定數量的結果。QuerySet
裏面可使用 limit()
和 skip()
這兩個方法來實現,可是更推薦使用數組切割的語法:
# Only the first 5 people users = User.objects[:5] # All except for the first 5 people users = User.objects[5:] # 5 users, starting from the 11th user found users = User.objects[10:15]
你能夠指定讓查詢返回一個結果。若是這個條在數據庫中不存在,那麼會引起 IndexError
錯誤 。使用 first()
方法在數據不存在的時候會返回 None
:
>>> # Make sure there are no users >>> User.drop_collection() >>> User.objects[0] IndexError: list index out of range >>> User.objects.first() == None True >>> User(name='Test User').save() >>> User.objects[0] == User.objects.first() True
Document
查詢默認狀況下,Document
的objects
屬性返回一個一個 QuerySet
對象,它並無進行任何篩選和過濾,它返回的是全部的數據對象。這一點能夠經過給一個 document
定義一個方法來修改 一個queryset
。這個方法須要兩參數__doc_cls
和 queryset
。第一個參數是定義這個方法的 Document
類名(從這個意義上來講,這個方法像是一個 classmethod()
而不是通常的方法),第二個參數是初始化的 queryset
。這個方法須要使用 queryset_manager()
來裝飾來它,使得它被承認。
class BlogPost(Document): title = StringField() date = DateTimeField() @queryset_manager def objects(doc_cls, queryset): # This may actually also be done by defining a default ordering for # the document, but this illustrates the use of manager methods return queryset.order_by('-date')
你不用調用 objects
方法,你能夠自定義更多的管理方法,例如:
class BlogPost(Document): title = StringField() published = BooleanField() @queryset_manager def live_posts(doc_cls, queryset): return queryset.filter(published=True) BlogPost(title='test1', published=False).save() BlogPost(title='test2', published=True).save() assert len(BlogPost.objects) == 2 assert len(BlogPost.live_posts()) == 1
當你想本身定義一些方法來過濾 document
的時候,繼承 QuerySet
類對你來講就是個好的方法。爲了在 document
裏面使用一個自定義的 QuerySet
類,你能夠在 document
裏的 meta
字典裏設置 queryset_class
的值來實現它。
class AwesomerQuerySet(QuerySet): def get_awesome(self): return self.filter(awesome=True) class Page(Document): meta = {'queryset_class': AwesomerQuerySet} # To call: Page.objects.get_awesome()
MongoDB 提供了開箱即用的聚合方法,但沒有 RDBMS 提供的那樣多。MongoEngine 提供了一個包裝過的內置的方法,同時自身提供了一些方法,它實現了在數據庫服務上執行的 Javascript 代碼的功能。
就像限制和跳過結果同樣, QuerySet
對象提供了用來計數的方法 - count()
,不過還有一個更 Pythonic
的方法來實現:
num_users = len(User.objects)
當你想爲 document
的特定的字段的數量計數的時候,可使用 sum()
:
yearly_expense = Employee.objects.sum('salary')
當你想求某個字段的平均值的時候,可使用 average()
:
mean_age = User.objects.average('age')
MongoEngine 提供了一個方法來獲取一個在集合裏 item
的頻率 - item_frequencies()
。下面一個例子能夠生成 tag-clouds
:
class Article(Document): tag = ListField(StringField()) # After adding some tagged articles... tag_freqs = Article.objects.item_frequencies('tag', normalize=True) from operator import itemgetter top_tags = sorted(tag_freqs.items(), key=itemgetter(1), reverse=True)[:10]
PASS
有時候使用關鍵字參數返回的 QuerySet
不能徹底知足你的查詢須要。例若有時候你須要將約束條件進行and
,or
的操做。你可使用 MongoEngine 提供的 Q
類來實現,一個 Q
類表明了一個查詢的一部分,裏面的參數設置與你查詢document
的時候相同。創建一個複雜查詢的時候,你須要用 &
或 |
操做符將 Q
對象連結起來。例如:
from mongoengine.queryset.visitor import Q # Get published posts Post.objects(Q(published=True) | Q(publish_date__lte=datetime.now())) # Get top posts Post.objects((Q(featured=True) & Q(hits__gte=1000)) | Q(hits__gte=5000))
MongoDB 文檔
能夠經過QuerySet
上的 update_one()
、update()
、modify()
方法自動更新。下面幾種操做符能夠被用到這幾種方法上:
set
– 設置成一個指定的值
unset
– 刪除一個指定的值
inc
– 將值加上一個給定的數
dec
– 將值減去一個給定的數
push
– 在 list
中添加一個值
push_all
– 在 list
中添加一個值
pop
– 移除list
的第一項或最後一項(根據 pop__<field>=val
中val
的值決定刪除第一項仍是最後一項,通常狀況下,val
爲負則刪除第一項,爲正則刪除最後一項,參見:mongodb $pop
pull
– 從 list
裏面移除一個值
pull_all
– 從 list
裏面移除個值
add_to_set
– 當要添加的值不在 list
中時,添加這個值
原子更新的語法相似於查詢語法,區別在於修飾操做符位於字段以前,而不是以後:
>>> post = BlogPost(title='Test', page_views=0, tags=['database']) >>> post.save() >>> BlogPost.objects(id=post.id).update_one(inc__page_views=1) >>> post.reload() # the document has been changed, so we need to reload it >>> post.page_views 1 >>> BlogPost.objects(id=post.id).update_one(set__title='Example Post') >>> post.reload() >>> post.title 'Example Post' >>> BlogPost.objects(id=post.id).update_one(push__tags='nosql') >>> post.reload() >>> post.tags ['database', 'nosql']
若是沒有修飾操做符,則默認爲$set
:
BlogPost.objects(id=post.id).update(title='Example Post') BlogPost.objects(id=post.id).update(set__title='Example Post')
能夠寫 Javascript函數,而後發送到服務器來執行。它返回結果是 Javascript 函數的返回值。這個功能是經過QuerySet()
對象的exec_js()
方法實現。傳遞一個包含一個Javascript函數的字符串做爲第一個參數。
其他位置的參數的名字字段將做爲您的Javascript函數的參數傳遞過去。
在 JavaScript 函數範圍中,一些變量可用:
collection
– 對應使用的 Document
類的集合的名稱
query
– 一個 QuerySet
對象
options
– 一個對象,它包含要傳遞給 exec_js()
函數的一些參數
def sum_field(document, field_name, include_negatives=True): code = """ function(sumField) { var total = 0.0; db[collection].find(query).forEach(function(doc) { var val = doc[sumField]; if (val >= 0.0 || options.includeNegatives) { total += val; } }); return total; } """ options = {'includeNegatives': include_negatives} return document.objects.exec_js(code, field_name, **options)