与Django一样,Document类都有一个 objects 属性。它用于将类与数据库关联起来。objects属性是一个QuerySetManager类型的对象,它的操作会返回一个QuerySet类型的对象。可以通过对QuerySet对象的迭代获取数据库中的数据。
class User(Document): name = StringField() country = StringField() class Paper(Document): content = StringField() author = ReferenceField(User) #这样写是一对一,如果想一对多的话应该这样写 author = listField(ReferenceField(User))
增加
user = User(email='223qq.com').save() #不知道pycharm为什么会显示语法错误 u1 = User.objects.filter(name='1').first() u2 = User.objects.fileter(name='1').fitst() page = Page(cotent='美丽的中国',author=[u1,u2].save()
查询
可以在查询是指定过滤条件以获取想要的结果。例如想要查询英国的用户: uk_users = User.objects(country='uk')
查询条件:
与Django类似,MongoEngine同样也提供了一些条件语句。
ne - 不相等
lt - 小于
lte - 小于等于
gt - 大于
gte - 大于等于
not - 取反
in - 值在列表中
nin - 值不在列表中
mod - 取模
all - 与列表的值相同
size - 数组的大小
exists - 字段的值存在
例如查询年龄小于等于18岁的用户: young_users = Users.objects(age__lte=18) 对于不同类型的数据提供了不同的条件语句。 查询结果个数限制 跟传统的ORM一样,MongoEngine也可以限制查询结果的个数。一种方法是在QuerySet对象上调用limit和skip方法;另一种方法是使用数组的分片的语法。例如: users = User.objects[10:15] users = User.objects.skip(10).limit(5)
嵌入文档查询
查询列表字段:
这个是在项目找那个遇到的,同事写的当时很费解,为什么有这种操作
还是举个例子吧:
# model class User(Document): name = StringField() age = StringField() class Login_token(EmbeddedDocument): value = StringField() class Session(Document): users = ListField(LazyReferenceField(User)) login_tokens = ListField(EmbeddedDocumentField(Login_token))
数据库数据库数据
# session { "_id" : ObjectId("5da0679f23641b6d95c09ef6"), "users" : [ ObjectId("5da0664b23641b6cc5500b63"), ObjectId("5da0663a23641b6cb946e986") ], "login_tokens" : [ { "value" : "1" }, { "value" : "2" } ] } ##user { "_id" : ObjectId("5da0663a23641b6cb946e986"), "name" : "小红" } /* 2 */ { "_id" : ObjectId("5da0664b23641b6cc5500b63"), "name" : "小李" }
题目要求:
查找value=1且name等于小红的session
ession = Session.objects.filter(login_tokens__value="1", users="5da0663a23641b6cb946e986") print(session)
结果:
[<Session: Session object>]
还有个例子
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') #他将查询列表中tags列表中包含coding的文档
还可以按照列表中的位置来查询
Page.objects(tags__0='db')
连表查询
在关系型数据库中我们用经常用连表查询,但是在MongoDB中,我们必须借助aggragate来实现连表,详细见下面的aggragate模块
元查询
有的程序员喜欢用pymongo原生的noSQL语句,在这里我们可以用__raw__来实现
It is possible to provide a raw PyMongo query as a query parameter, which will be integrated directly into the query. This is done using the __raw__ keyword argument: Page.objects(__raw__={'tags': 'coding'})
自定义查询
mongo中还支持自定义查询
class AwesomerQuerySet(QuerySet): def get_awesome(self): return self.filter(awesome=True) class Page(Document): meta = {'queryset_class': AwesomerQuerySet} #在meta中自定义查询的类 # To call: Page.objects.get_awesome()
引用
引用这个知识点我是在学了mongoengin好长时间才真正的理解会运用,具体来看实例
# model class OperationLogging(db.DynamicDocument): """操作日志""" operate_time = db.IntField(default=now_timestamp) operate_obj = db.StringField() operator = db.LazyReferenceField('Users') shop = db.LazyReferenceField('Shops') operate_type = db.StringField() operate_result = db.StringField() class Machines(db.DynamicDocument): """售货机基类""" imei = db.StringField() type = db.IntField() shop = db.LazyReferenceField('Shops') status = db.IntField() note = db.StringField() creator = db.LazyReferenceField('Users') class Pipeline(db.EmbeddedDocument): """售货机货道(即每个格子)""" id = db.IntField() product = db.LazyReferenceField('Products') stock = db.IntField() max_stock = db.IntField() pipelines = db.ListField(db.EmbeddedDocumentField(Pipeline))
这里有两个数据库模型类
题目要求我们已经得到一个机器对象即
machine_obj = Machines.objects(id=machine_id, deleted=False).first()
现在我们要添加操作日志记录
obj = OperationLogging.objects.create(operate_obj=operate_obj, operator=operator, shop=?,operate_type=operate_type,operate_result=operate_result)
操作日志中的shop我们应该怎么获取?显然我们已经知道通过machine_obj可以得到shop,具体有两种方式都可以实现
#方式一 machine_obj.shop 得到的是一个 <class 'mongoengine.base.datastructures.LazyReference'> 这个可以直接放在LazyReferenceField对应的值上 obj = OperationLogging.objects.create(operate_obj=operate_obj, operator=operator, shop=machine_obj.shop, operate_type=operate_type, operate_result=operate_result) #方式二:machine_obj.shop.fetch() 得到的就是一个<class 'models.Shops'>,这个类对象可以当做引用对象直接用,可以放在LazyReferenceField对应的值上 obj = OperationLogging.objects.create(operate_obj=operate_obj, operator=operator, shop=machine_obj.shop.fetch(), operate_type=operate_type, operate_result=operate_result)
其实还有第三种方法:前提是你得到shop的具体对象时(object)
#方法三 :直接一个shop对象也可以放在LazyReferenceField对应的值上 shop_obj = Shops.objects.filter(id=1111,deleted).first() obj = OperationLogging.objects.create(operate_obj=operate_obj, operator=operator, shop=shop_obj, operate_type=operate_type, operate_result=operate_result)
注意:一个引用可以用fetch()得到这个对象并点出相应的属性
Aggregation聚合查询
MongoEngine提供了一些数据库的聚合操作。在文章MongoDB基础中也有这个方法的介绍.地址:https://www.cnblogs.com/sticker0726/articles/11121745.html#_label5
注意:在经过aggregate查询后得到的是一个迭代器.含有__iter__和next方法
<class 'pymongo.command_cursor.CommandCursor'>
统计结果个数即可以使用QuerySet的count方法,也可以使用Python风格的方法:
num_users = len(User.objects) num_users = User.objects.count() 其他的一些聚合操作。 求和: yearly_expense = Employee.objects.sum('salary') 求平均数: mean_age = User.objects.average('age')
连表查询例题
#查询作者为中国的page #在Django的orm中我们我可以直接这样查 uk_papers = Paper.objects(author__country='中国') #但是在mongoengine中我们不可以这么查要这样=查 pipeline = [ {'$lookup': { 'from': "user1", 'localField': "author", 'foreignField': '_id', 'as': 'authors' }}, {'$match': {'authors.country': "中国"}} # 这里一定要用我们在as属性中设置的属性值,不要用author ] o = Paper1.objects.aggregate(*pipeline) for i in o: print(i)
结果为:
{'_id': ObjectId('5db1090c23641b35a04cfe45'), 'content': '美丽的中国', 'author': ObjectId('5db108c923641b353c6d8340'), 'authors': [{'_id': ObjectId('5db108c923641b353c6d8340'), 'name': '1', 'country': '中国'}]} ####注意authors的属性值是列表
高级查询
有时需要将多个条件进行组合,比如或查询,在mongoengine中没有or,这个语法,前面提到的方法就不能满足需求了。这时可以使用MongoEngine的Q类。它可以将多个查询条件进行 &(与) 和 |(或) 操作。
例如下面的语句是查询所有年龄大于等于18岁的英国用户,或者所有年龄大于等于20岁的用户。
User.objects((Q(country='uk') & Q(age__gte=18)) | Q(age__gte=20))
在项目中遇到的情况,对于订单列表来说,销售员只能看到自己及下属的订单,所以查询语句为:
staff_query = Q(user_role__lt=g.current_login_user.role) | Q(user=ObjectId(g.current_login_user.pk)) # 查询 orders_qs = Orders.objects(staff_query).filter(**query)#**query中有一些条件,比如店铺id
更新
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 中时,添加这个值
DatedPage.objects(title='你好').update(title='大家好') # 操作成功返回0 DatedPage.objects(title='你好1').update_one(set__title='红楼梦')
>>> 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')
浙公网安备 33010602011771号