MongoDB 聚合查询优化:$match、$lookup 和 double $unwind

时间:2021-01-31 15:58:56

标签: mongodb mongodb-query aggregation-framework pymongo pymongo-3.x

假设我们有两个集合:

  • devices:该集合中的对象具有(除其他外)字段 name(字符串)和 cards(数组);该数组中的每个部分都有字段 modelslot。卡片不是另一个集合,它只是一些嵌套数据。
  • interfaces:该集合中的对象具有(除其他外)字段 nameowner

额外信息:

  • 对于 cards,我只对 slot 是数字的那些感兴趣
  • 对于与前一个条件匹配的 partdevice,在另一个集合中有一个 interface 对象,其中 owner 字段的值为 {{原因中的 name 的 1}} 且名称为 device(字符 's' + 该部分的插槽 + 'p1')

我的工作是创建一个查询以生成所有这些设备中所有现有卡的摘要,每个条目都包含来自 s[slot]p1 集合的信息。我还需要能够对查询进行参数化(以防我只对具有特定名称的特定设备感兴趣,仅对卡片的特定型号等感兴趣)

到目前为止,我有这个:

interfaces

查询有效并且速度非常快,但我有一个问题:

  1. 有什么办法可以避免第二个mongo_client.devices.aggregate([ # Retrieve all the devices having the cards field { "$match": { # "name": "<device-name>", "cards": { "$exists": "true" } } }, # Group current content with every cards object { "$unwind": "$cards" }, # Only take the ones having "slot" a number { "$match": { "cards.slot": { "$regex": "^\d+$" } } }, # Retrieve the device's interfaces { "$lookup": { "from": "interfaces", "let": { "owner": "$name", }, "as": "interfaces", "pipeline": [{ "$match": { "$expr": { "$eq": ["$owner", "$$owner"] }, }, }] } }, { "$unwind": "$interfaces" }, { "$match": { "$expr": { "$eq": ["$interfaces.name", { "$concat": ["s", "$cards.slot", "p1"] }] } } }, # Build the final object { "$project": { # Card related fields "slot": "$cards.slot", "model": "$cards.model", # Device related fields "device_name": "$name", # Fields from interfaces "interface_field_x": "$interfaces.interface_field_x", "interface_field_y": "$interfaces.interface_field_y", } }, ]) ?如果每个 $unwind 有 50-150 个 device 对象,其中 interface 是该设备的名称,我觉得我正在减慢它的速度。每个设备都有一个名为 owner 的唯一接口。如何以更好的方式获得该特定对象?我试图在 s[slot]p1 甚至 $eq$match 内部的 $lookup 中使用两个 $regex 表达式,但我无法使用外部 {{1 }} 字段,即使我把它放在 $regexMatch 中。

  2. 如果我想参数化我的查询以在需要时过滤数据,您会添加匹配表达式作为中间步骤还是只在最后过滤?

欢迎对查询进行任何其他改进。我也对如何证明错误很感兴趣(如果错误地缺少 slot 或找不到 let 接口。

谢谢!

1 个答案:

答案 0 :(得分:1)

您的问题缺少查询的示例数据,但是:

  • 将第三阶段合并到第一阶段,去掉 $exists
  • 使用 localField+foreignField 代替管道,管道要慢得多

查询中展开的次数应与您想要在结果集中的对象相对应:

  • 0 次设备展开
  • 1 张卡片放松
  • 2 个接口展开

为了匹配所需的条件,不需要展开。

相关问题