MongoDB ORM:MongoEngine
1 MongoEngine 初体验
# 用户信息
class User(Document):
name = SringField()
gender = BooleanField()
age = IntField()
website = StringField()
hobby = ListField(EmbeddedDocumentField(Hobby))
tags = ListField(StringField())
# 爱好信息,嵌入文档类
class Hobby(EmbeddedDocument):
name = StringField()
sort = StringField()
sustain = FloatField()
myhobby1 = Hobby(name="reading book", sort="good", sustain=8.5)
myhobby2 = Hobby(name="play LOL", sort="bad", sustain=2.6)
myhobby = [myhobby1, myhobby2]
Soloman = User(name="Solomanxbr", gender=True, age=18, website="https://www.soloman.vip", hobby=myhobby, tags=["Python", "Database", "MongoDB"])
# 可以通过调用 QuerySet 对象的关键字参数来对数据查询进行查询过滤,关键字查询中的键和你想要查询的 Document 中的字段一致
users = User.objects(name="Solomanxbr")
# 对于内嵌EmbeddedDocument的字段可以使用 __ 来代替对象属性访问语法中的.进行访问
# 查询Soloman所有分类为good的hobby
Soloman_good_hobby = User.objects(hobby__sort="good")
# 在查询中也可以使用各种操作符,只要将其加在查询关键字的双下划线 __ 之后即可:
# 查询所有hobby中坚持时间大于等于5年的
long_time_hobby = Hobby.objects(sustain__gte=5.0)
# 你可以通过__raw__参数来使用一个原始的 PyMongo 语句来进行查询,这样可以进行原始的完整查询:
Soloman = User.objects(__raw__={"name": "Solomanxbr"})
# 等同于
Soloman = User.objects(name="Solomanxbr")
# 有时候需要限制返回的结果的数量,或者需要跳过一定数量的结果。QuerySet 里面可以使用 limit() 和 skip() 这两个方法来实现,但是更推荐使用数组切片的语法
users = User.objects(age_gte=18).limit(5)
users = User.objects(age_gte=18)[:5]
users = User.objects(age_gte=18).skip(2)
users = User.objects(age_gte=18)[2:]
users = User.objects(age_gte=18)[1]
# 使用数组切片时如果这个语句在数据库中查询不到数据,那么会引发 IndexError 错误
# 使用 first() 方法在数据不存在的时候会返回 None
users = User.objects(age_gte=18).first()
默认 Document 查询情况下,Document 的 objects 属性返回一个一个 QuerySet 对象,它并没有进行任何筛选和过滤,它返回的是所有的数据对象。可以通过给一个 document 定义一个方法来修改 一个 queryset 。这个方法需要两参数 doc_cls 和 queryset 。第一个参数是定义这个方法的 Document 类名,第二个参数是初始化的 queryset。这个方法需要使用 queryset_manager() 来装饰来它。
# 用户信息
class User(Document):
name = SringField()
gender = BooleanField()
age = IntField()
website = StringField()
hobby = ListField(EmbeddedDocumentField(Hobby))
# 自定义返回user按照age逆序(年龄由大到小)排序的结果
@queryset_manager
def object(doc_cls, queryset):
return queryset.order_by("-age")
# 不一定要覆盖objects, 也可自定义更多自己的方法
@queryset_manager
def order_by_age(doc_cls, queryset):
return queryset.order_by("+age")
old_to_young = User.objects(gender=True)
young_to_old = User.order_by_age(gender=True)
上面的方法是修改了QuerySet 后返回,还可以自定义QuerySet进行各种自主操作。当你想自己定义一些方法来过滤 document 的时候,可以继承 QuerySet 类。为了在 document 里面使用一个自定义的 QuerySet 类,你可以在 document 里的 meta 字典里设置 queryset_class 的值来实现它。
# 自定义的 QuerySet 类: SolomanQuerySet
class SolomanQuerySet(QuerySet):
def get_female_user():
return self.filter(gender=False)
# 用户信息
class User(Document):
name = SringField()
gender = BooleanField()
age = IntField()
website = StringField()
hobby = ListField(EmbeddedDocumentField(Hobby))
meta = {'queryset_class': SolomanQuerySet}
tags = ListField(StringField())
female_user = User.objects.get_female_user()
2 Aggregation 聚合函数
# 返回数据的数量
male_user_sum = User.objects(gender=True).count()
male_user_sum = len(User.objects(gender=True))
# 当你想为 document 的特定的字段进行统计的时候,可以使用 sum()
user_age_sum = User.objects.sum("age")
# 求所有用户的平均年龄
user_age_avg = User.objects.average("age")
# MongoEngine 提供了一个方法来获取一个 item 在集合里的频率 - item_frequencies()
tags_freq = User.objects.item_frequencies("tags", normalize=True)
**联合多个条件查询:**有时候使用关键字参数返回的 QuerySet 不能完全满足查询需要。例如有时候你需要将约束条件进行 and,or 的操作。你可以使用 MongoEngine 提供的 Q 类来实现,一个 Q 类代表了一个查询的一部分条件,里面的参数设置与你平时查询 document 的时候相同。建立一个复杂查询的时候,用 & 或 | 操作符将 Q 对象连结起来即可。
# 查询年龄小于18或年龄大于60的用户
special_age_user = User.object(Q(age__lt=18) & Q(age__gt=60))
**原子更新:**MongoDB 文档可以通过 QuerySet 上的 update_one()、update()、modify() 方法自动更新。下图中的操作符可以被用到这几种方法上。原子更新的语法类似于查询语法,区别在于修饰操作符位于字段__之前,而不是之后。没有修饰操作符时,默认为set。
Soloman = User(name="Solomanxbr", gender=True, age=18, website="https://www.soloman.vip", hobby=myhobby, tags=["Python", "Web", "MongoDB"])
Soloman.save()
# 更新名字
User.objects(name="Solomanxbr").update_one(set__name="Supermanxbr")
Soloman.reload()
Soloman.name # Supermanxbr
# 年龄+2
User.objects(name="Solomanxbr").update_one(inc__age=2)
Soloman.reload()
Soloman.age # 20
# 给tags列表增加一个元素
User.objects(name="Solomanxbr").update_one(push__tags="Java")
Soloman.reload()
Soloman.tags # ["Python", "Web", "MongoDB", "Java"]
3 常用 API
# to_json():将文档对象转换为json字符串
Soloman_json_fotmat = User.objects(name="Solomanxbr").to_json()
# as_pymongo():我们mongoengine查询返回的是一个文档对象,但是一般要把数据json后发给前端,而文档对象json速度慢,这时候就出来as_pymongo方法了
# 它返回的不是document对象,而是pymongo的元数据,是直接可用的包含多个Python字典的列表。对于提高搜索性能十分有利,前提是间接引用不能用了
Soloman_python_fotmat = User.objects(name="Solomanxbr").as_pymongo()
# only():只会返回括号内的字段,提高了查询内容的速度
# 只返回名字和年龄
Soloman_only_fotmat = User.objects(name="Solomanxbr").only("name").only("age")