我有2个DynamicDocuments:
class Tasks(db.DynamicDocument):
task_id = db.UUIDField(primary_key=True,default=uuid.uuid4)
name = db.StringField()
flag = db.IntField()
class UserTasks(db.DynamicDocument):
user_id = db.ReferenceField('User')
tasks = db.ListField(db.ReferenceField('Tasks'),default=list)
我希望通过检查给定task_id的UserTasks
值(来自任务文档)是flag
还是0
来过滤1
文档,给定task_id和用户身份。所以我用以下方式查询: -
obj = UserTasks.objects.get(user_id=user_id,tasks=task_id)
这会抓取一个UserTask
对象。
现在我循环遍历任务列表,首先我获得等效任务,然后按以下方式检查其标志值。
task_list = obj.tasks
for t in task_list:
if t['task_id'] == task_id:
print t['flag']
是否有更好/直接的方式查询UserTasks
文档以获取任务文档的标记值。
PS:我可以直接从Tasks
文档中获取标记值,但我还需要检查该任务是否与用户相关联。因此,我直接查询了USerTasks
文档。
答案 0 :(得分:2)
我们可以直接过滤单个查询中包含ReferenceField's
字段的文档吗?
不,无法使用ReferenceField
字段直接过滤文档,因为这样做会需要连接,而mongodb不支持连接。
根据database references:上的MongoDB文档
MongoDB不支持连接。在MongoDB中,一些数据被非规范化, 或者与文档中的相关数据一起存储以消除对连接的需要。
来自官方网站上的另一个page:
如果我们使用关系数据库,我们可以执行连接 用户和商店,并在一个查询中获取所有对象。的但 MongoDB不支持连接,因此有时需要一点点 反规范化。强>
关系纯粹主义者可能已经感到不安,就好像我们一样 违反一些普遍法律。但是请记住MongoDB 集合不等同于关系表;每个服务一个 独特的设计目标。规范化表提供原子, 孤立的数据块。然而,一份文件更为贴切 一个整体的对象。
因此,在1个查询中,我们无法在tasks
模型上使用特定标记值和给定user_id
和task_id
过滤UserTasks
。
如何执行过滤?
要按照所需条件执行过滤,我们需要执行2次查询。
在第一个查询中,我们会尝试使用给定的Tasks
和task_id
过滤flag
模型。然后,在第二个查询中,我们将使用给定的UserTasks
和从第一个查询中检索到的user_id
过滤task
模型。
示例:强>
假设我们有user_id
,task_id
,我们需要检查相关任务的flag
值是否为0
。
第一次查询
我们将首先使用给定my_task
和task_id
作为flag
来检索0
。
my_task = Tasks.objects.get(task_id=task_id, flag=0) # 1st query
第二次查询
然后在第二个查询中,您需要使用给定的UserTask
和user_id
对象过滤my_task
模型。
my_user_task = UserTasks.objects.get(user_id=user_id, tasks=my_task) # 2nd query
只有获得具有给定my_task
和task_id
值的flag
对象时,才应执行第二次查询。此外,如果没有匹配的对象,您将需要添加错误处理。
如果EmbeddedDocument
模型使用了Tasks
怎么办?
假设我们已将Tasks
文档定义为EmbeddedDocument
,将tasks
模型中的UserTasks
字段定义为EmbeddedDocumentField
,然后执行所需操作过滤我们可以做类似下面的事情:
my_user_task = UserTasks.objects.get(user_id=user_id, tasks__task_id=task_id, tasks__flag=0)
从任务列表中获取特定my_task
上述查询将返回一个UserTask
文档,其中包含所有tasks
。然后我们需要执行某种迭代来获得所需的任务。
为此,我们可以使用enumerate()
执行列表理解。
然后,所需的索引将是返回的1元素列表的第1个元素。
my_task_index = [i for i,v in enumerate(my_user_task.tasks) if v.flag==0][0]
答案 1 :(得分:0)
@Praful,根据您的架构,您需要两个查询,因为mongodb没有连接,所以如果您想获得"所有数据"在一个查询中,您需要一个适合该情况的模式。 ReferenceField是一个特殊字段,它执行其他集合的延迟加载(它需要查询)。
根据您需要的查询,我建议您更改架构以适应这种情况。 NOSQL引擎背后的想法是"非规范化"所以有一个EmbeddedDocument列表也不错。 EmbeddedDocument可以是一个较小的文档(非规范化版本),包含一组字段而不是所有字段。
如果您不想在查询时将整个文档加载到内存中,可以使用"投影"排除这些字段。 使用UserTasks有一个EmbeddedDocument列表,其中包含您可以执行的任务:
UserTasks.objects.exclude('tasks').filter(**filters)
我希望它可以帮到你。
祝你好运!