首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB聚合查询优化:$match、$lookup和double $unwind

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

Stack Overflow用户
提问于 2021-01-31 15:58:56
回答 1查看 470关注 0票数 0

假设我们有两个收藏品:

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

额外信息:

  • for cards,我只感兴趣的是,slot是与前一条件相匹配的devicepart的数字
  • ,在另一个集合中,owner字段的值为device的值,其名称为D26(字符s‘+该部分的槽)H 227f 228/code>

我的工作是创建一个查询,以生成所有这些设备中所有现有卡的摘要,每个条目都被来自interfaces集合的信息丰富。我还需要能够将查询参数化(如果我只对某个具有特定名称的设备感兴趣,只对卡片的某个模型感兴趣,等等)。

到目前为止,我有这样的想法:

代码语言:javascript
复制
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",
        }
    },
])

这个查询运行得很快,但我有一个问题:

  1. ,我有什么办法可以避开第二$unwind吗?如果每一个device都有50-150个interface对象,其中owner是该设备的名称,那么我觉得我正在放慢速度。每个设备都有一个名为s[slot]p1的唯一接口。我怎样才能以更好的方式得到特定的对象?我尝试在let.

内部的$match中使用两个$eq表达式,甚至在$regex或$regexMatch中使用,但是我不能使用外部slot字段,即使我把它放在了$lookup中

  1. 如果我想参数化我的查询以过滤数据,如果需要的话,您是添加匹配表达式作为中间步骤还是只在末尾进行筛选?

欢迎对查询进行任何其他改进。我还感兴趣的是如何证明错误(如果错误地丢失了cards或找不到s1p1接口)。

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-31 16:38:27

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

$exists

  • Instead
  • 将第三阶段合并到第一阶段,去掉流水线使用的localField+foreignField,

要慢得多。

查询中的展开次数应对应于结果集中所需的对象:

  • 0为设备展开
  • 1为卡展开
  • 2接口

为了满足所需的条件,不需要松开。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65981184

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档