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)