Mongo嵌入式文档查询

Pyt*_*ast 5 python mongodb mongoengine mongodb-query

我有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)
Run Code Online (Sandbox Code Playgroud)

我想UserTasks通过检查flag给定task_id 的值(来自Tasks Document)是否为0或者1给定task_id和user_id 来过滤文档.所以我用以下方式查询: -

obj = UserTasks.objects.get(user_id=user_id,tasks=task_id)
Run Code Online (Sandbox Code Playgroud)

这会抓住我一个UserTask对象.

现在我循环遍历任务列表,首先我获得等效任务,然后按以下方式检查其标志值.

task_list = obj.tasks
for t in task_list:
    if t['task_id'] == task_id:
        print t['flag']
Run Code Online (Sandbox Code Playgroud)

是否有更好/直接的方式查询UserTasksDocument以获取Tasks Document的标志值.

PS:我可以从TasksDocument 直接获取标志值,但我还需要检查任务是否与用户相关联.因此我直接查询了该USerTasks文件.

Rah*_*pta 4

ReferenceField\'s我们可以直接使用单个查询中的字段来过滤文档吗?

\n\n

不,不可能直接使用 字段过滤文档,ReferenceField因为这样做需要联接,而 mongodb 不支持联接。

\n\n

根据数据库参考的 MongoDB 文档:

\n\n
\n

MongoDB 不支持联接。在 MongoDB 中,一些数据被非规范化,或者与相关数据一起存储在文档中,以消除连接的需要。

\n
\n\n

从官方网站的另一个页面:

\n\n
\n

如果我们使用关系数据库,我们可以对用户和商店执行联接,并在单个查询中获取所有对象。但是 MongoDB 不支持连接,因此有时需要一些非规范化。

\n\n

关系纯粹主义者可能已经感到不安了,就好像我们违反了某些普遍法则。但让\xe2\x80\x99s记住,MongoDB\n集合并不等同于关系表;每一个都服务于独特的设计目标。规范化表提供原子、独立的数据块。然而,文档更接近地表示一个对象作为一个整体。

\n
\n\n

因此,在 1 个查询中,我们不能同时tasks使用特定标志值和模型上给定的user_id和进行过滤。task_idUserTasks

\n\n

那么如何进行过滤呢?

\n\n

为了根据所需条件执行过滤,我们需要执行 2 个查询。

\n\n

在第一个查询中,我们将尝试使用Tasks给定的task_id和来过滤模型flag。然后,在第二个查询中,我们将UserTasks使用给定的user_idtask从第一个查询中检索到的模型来过滤模型。

\n\n

例子:

\n\n

假设我们有一个user_idtask_id我们需要检查相关任务的flag值是否为0

\n\n

第一个查询

\n\n

我们将首先使用my_task给定的task_idflagas 检索0

\n\n
my_task = Tasks.objects.get(task_id=task_id, flag=0) # 1st query\n
Run Code Online (Sandbox Code Playgroud)\n\n

第二次查询

\n\n

UserTask然后在第二个查询中,您需要使用给定的模型user_id和对象来过滤模型my_task

\n\n
my_user_task = UserTasks.objects.get(user_id=user_id, tasks=my_task) # 2nd query\n
Run Code Online (Sandbox Code Playgroud)\n\n

仅当您获得my_task具有给定task_id和的对象时才应执行第二个查询flag,才应执行第二个查询。此外,您还需要添加错误处理,以防没有匹配的对象。

\n\n

如果我们已经使用了怎么EmbeddedDocumentTasks呢?

\n\n

假设我们已将Tasks文档定义为 anEmbeddedDocument并将模型tasks中的字段定义UserTasks为 anEmbeddedDocumentField,那么为了进行所需的过滤,我们可以执行如下操作:

\n\n
my_user_task = UserTasks.objects.get(user_id=user_id, tasks__task_id=task_id, tasks__flag=0)\n
Run Code Online (Sandbox Code Playgroud)\n\n

获取特定的my_task从任务列表中

\n\n

上面的查询将返回一个UserTask文档,其中包含所有tasks. 然后我们需要执行某种迭代以获得所需的任务。

\n\n

为此,我们可以使用以下命令执行列表理解enumerate()。\n那么所需的索引将是返回的 1 元素列表的第一个元素。

\n\n
my_task_index = [i for i,v in enumerate(my_user_task.tasks) if v.flag==0][0]\n
Run Code Online (Sandbox Code Playgroud)\n