MongoEngine 查詢(翻譯)

數據庫查詢

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 查詢

默認狀況下,Documentobjects 屬性返回一個一個 QuerySet 對象,它並無進行任何篩選和過濾,它返回的是全部的數據對象。這一點能夠經過給一個 document 定義一個方法來修改 一個queryset 。這個方法須要兩參數__doc_clsqueryset 。第一個參數是定義這個方法的 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

自定義 QuerySets

當你想本身定義一些方法來過濾 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()

Aggregation 聚合

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 不能徹底知足你的查詢須要。例若有時候你須要將約束條件進行andor 的操做。你可使用 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))

Atomic updates(原子更新)

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函數,而後發送到服務器來執行。它返回結果是 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)
相關文章
相關標籤/搜索