Mongo 嵌入式文档查询
Mongo Embedded Document 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)
我想通过检查给定 task_id 的 flag
值(来自任务文档)是 0
还是 [=17= 来过滤 UserTasks
文档],给定 task_id 和 user_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']
是否有任何better/direct查询UserTasks
文档的方法以获取任务文档的标志值。
PS :我可以直接从 Tasks
文档中获取标志值,但我还需要检查任务是否与用户相关联。于是直接查询了USerTasks
文档
@Praful,根据您的架构,您需要两个查询,因为 mongodb 没有连接,所以如果您想在一个查询中获得 "all the data",您需要一个适合这种情况的架构。
ReferenceField 是一个特殊的字段,它对另一个集合进行延迟加载(它需要查询)。
根据您需要的查询,我建议您更改架构以适应该查询。 NOSQL 引擎背后的想法是 "denormalization" 所以拥有一个 EmbeddedDocument 列表也不错。 EmbeddedDocument 可以是一个较小的文档(非规范化版本),具有一组字段而不是所有字段。
如果您不想在查询时将整个文档加载到内存中,您可以使用 "projection" 排除那些字段。
假设您的 UserTasks 有一个 EmbeddedDocument 列表,其中包含您可以执行的任务:
UserTasks.objects.exclude('tasks').filter(**filters)
希望对你有所帮助
祝你好运!
我们能否在单个查询中直接过滤具有 ReferenceField's
字段的文档?
不, 无法直接使用 ReferenceField
字段过滤文档,因为这样做需要连接,而 mongodb 不支持连接.
上的 MongoDB 文档
MongoDB does not support joins. In MongoDB some data is denormalized,
or stored with related data in documents to remove the need for joins.
来自官方网站上的另一个page:
If we were using a relational database, we could perform a join on
users and stores, and get all our objects in a single query. But
MongoDB does not support joins and so, at times, requires bit of
denormalization.
Relational purists may be feeling uneasy already, as if we were
violating some universal law. But let’s bear in mind that MongoDB
collections are not equivalent to relational tables; each serves a
unique design objective. A normalized table provides an atomic,
isolated chunk of data. A document, however, more closely represents
an object as a whole.
因此,在 1 个查询中,我们不能同时使用特定标志值和 UserTasks
模型上的给定 user_id
和 task_id
来过滤 tasks
。
那么如何进行过滤呢?
要根据要求的条件执行过滤,我们需要执行 2 个查询。
在第一个查询中,我们将尝试使用给定的 task_id
和 flag
过滤 Tasks
模型。然后,在第二个查询中,我们将使用给定的 user_id
和从第一个查询中检索到的 task
过滤 UserTasks
模型。
示例:
假设我们有一个 user_id
、task_id
,我们需要检查相关任务的 flag
值是否为 0
。
第一次查询
我们将首先使用给定的 task_id
和 flag
检索 my_task
作为 0
.
my_task = Tasks.objects.get(task_id=task_id, flag=0) # 1st query
第二次查询
然后在第二个查询中,您需要使用给定的 user_id
和 my_task
对象过滤 UserTask
模型。
my_user_task = UserTasks.objects.get(user_id=user_id, tasks=my_task) # 2nd query
仅当您获得具有给定 task_id
和 flag
值的 my_task
对象时,才应执行第二个查询。此外,如果没有匹配的对象,您将需要添加错误处理。
如果我们对 Tasks
模型使用了 EmbeddedDocument
会怎样?
假设我们已经将 Tasks
文档定义为 EmbeddedDocument
并将 UserTasks
模型中的 tasks
字段定义为 EmbeddedDocumentField
,然后执行我们可以做如下所需的过滤:
my_user_task = UserTasks.objects.get(user_id=user_id, tasks__task_id=task_id, tasks__flag=0)
从任务列表中获取特定的 my_task
以上查询将 return 一个 UserTask
文档,其中将包含所有 tasks
。然后我们需要执行某种迭代来获得所需的任务。
为此,我们可以使用 enumerate()
执行列表理解。
那么所需的索引将是 1 元素列表的第一个元素 returned.
my_task_index = [i for i,v in enumerate(my_user_task.tasks) if v.flag==0][0]
我有 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 的 flag
值(来自任务文档)是 0
还是 [=17= 来过滤 UserTasks
文档],给定 task_id 和 user_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']
是否有任何better/direct查询UserTasks
文档的方法以获取任务文档的标志值。
PS :我可以直接从 Tasks
文档中获取标志值,但我还需要检查任务是否与用户相关联。于是直接查询了USerTasks
文档
@Praful,根据您的架构,您需要两个查询,因为 mongodb 没有连接,所以如果您想在一个查询中获得 "all the data",您需要一个适合这种情况的架构。 ReferenceField 是一个特殊的字段,它对另一个集合进行延迟加载(它需要查询)。
根据您需要的查询,我建议您更改架构以适应该查询。 NOSQL 引擎背后的想法是 "denormalization" 所以拥有一个 EmbeddedDocument 列表也不错。 EmbeddedDocument 可以是一个较小的文档(非规范化版本),具有一组字段而不是所有字段。
如果您不想在查询时将整个文档加载到内存中,您可以使用 "projection" 排除那些字段。 假设您的 UserTasks 有一个 EmbeddedDocument 列表,其中包含您可以执行的任务:
UserTasks.objects.exclude('tasks').filter(**filters)
希望对你有所帮助
祝你好运!
我们能否在单个查询中直接过滤具有 ReferenceField's
字段的文档?
不, 无法直接使用 ReferenceField
字段过滤文档,因为这样做需要连接,而 mongodb 不支持连接.
MongoDB does not support joins. In MongoDB some data is denormalized, or stored with related data in documents to remove the need for joins.
来自官方网站上的另一个page:
If we were using a relational database, we could perform a join on users and stores, and get all our objects in a single query. But MongoDB does not support joins and so, at times, requires bit of denormalization.
Relational purists may be feeling uneasy already, as if we were violating some universal law. But let’s bear in mind that MongoDB collections are not equivalent to relational tables; each serves a unique design objective. A normalized table provides an atomic, isolated chunk of data. A document, however, more closely represents an object as a whole.
因此,在 1 个查询中,我们不能同时使用特定标志值和 UserTasks
模型上的给定 user_id
和 task_id
来过滤 tasks
。
那么如何进行过滤呢?
要根据要求的条件执行过滤,我们需要执行 2 个查询。
在第一个查询中,我们将尝试使用给定的 task_id
和 flag
过滤 Tasks
模型。然后,在第二个查询中,我们将使用给定的 user_id
和从第一个查询中检索到的 task
过滤 UserTasks
模型。
示例:
假设我们有一个 user_id
、task_id
,我们需要检查相关任务的 flag
值是否为 0
。
第一次查询
我们将首先使用给定的 task_id
和 flag
检索 my_task
作为 0
.
my_task = Tasks.objects.get(task_id=task_id, flag=0) # 1st query
第二次查询
然后在第二个查询中,您需要使用给定的 user_id
和 my_task
对象过滤 UserTask
模型。
my_user_task = UserTasks.objects.get(user_id=user_id, tasks=my_task) # 2nd query
仅当您获得具有给定 task_id
和 flag
值的 my_task
对象时,才应执行第二个查询。此外,如果没有匹配的对象,您将需要添加错误处理。
如果我们对 Tasks
模型使用了 EmbeddedDocument
会怎样?
假设我们已经将 Tasks
文档定义为 EmbeddedDocument
并将 UserTasks
模型中的 tasks
字段定义为 EmbeddedDocumentField
,然后执行我们可以做如下所需的过滤:
my_user_task = UserTasks.objects.get(user_id=user_id, tasks__task_id=task_id, tasks__flag=0)
从任务列表中获取特定的 my_task
以上查询将 return 一个 UserTask
文档,其中将包含所有 tasks
。然后我们需要执行某种迭代来获得所需的任务。
为此,我们可以使用 enumerate()
执行列表理解。
那么所需的索引将是 1 元素列表的第一个元素 returned.
my_task_index = [i for i,v in enumerate(my_user_task.tasks) if v.flag==0][0]