【问题标题】:$filter inside $reduce or inside $map from array without unwind$filter 内 $reduce 或 $map 内来自数组而不展开
【发布时间】:2022-02-05 00:56:24
【问题描述】:

我需要一些帮助: 我想优化这个查询更快,它需要通过 events.eventType:"log" 过滤所有带有 server:"strong" 的文档,但没有单独的展开和过滤阶段,也许在 $reduce 阶段以某种方式添加 $filter .

示例单个文档:

 {
 server: "strong",
 events: [
  {
    eventType: "log",
    createdAt: "2022-01-23T10:26:11.214Z",
    visitorInfo: {
      visitorId: "JohnID"
    }
  }

当前聚合查询:

   db.collection.aggregate([
   {
    $match: {
    server: "strong"
    }
   },
   {
    $project: {
     total: {
      $reduce: {
      input: "$events",
      initialValue: {
        visitor: [],
        uniquevisitor: []
      },
      in: {
        visitor: {
          $concatArrays: [
            "$$value.visitor",
            [
              "$$this.visitorInfo.visitorId"
            ]
          ]
        },
        uniquevisitor: {
          $cond: [
            {
              $in: [
                "$$this.visitorInfo.visitorId",
                "$$value.uniquevisitor"
              ]
            },
            "$$value.uniquevisitor",
            {
              $concatArrays: [
                "$$value.uniquevisitor",
                [
                  "$$this.visitorInfo.visitorId"
                ]
              ]
            }
          ]
          }
        }
       }
      }
    }
    }
    ])

预期输出,两个具有唯一 visitorId 的列表和所有 visitorId 的列表:

 [
{
"total": {
  "uniquevisitor": [
    "JohnID"
  ],
  "visitor": [
    "JohnID",
    "JohnID"
  ]
}

} ]

playground

在示例查询中没有为 events.eventType:"log" 添加过滤器,如果没有 $unwind 怎么实现?

【问题讨论】:

  • (1) 一件事是在初始匹配阶段包含此过滤器 - 这有助于仅选择至少有一个匹配 events.eventType:"log" 的文档(这是假设可以有文档没有任何events.eventType: ''log')。 (2) 更快的查询 - 您可以选择在初始匹配阶段定义字段索引。 (3) 数组运算符$filter$map$reduce 可以嵌套或一起使用——例如,您可以使用$let 在同一个$addFields 阶段中​​的多个步骤中执行数组操作。
  • 这是我尝试在 $map 或 $reduce 中实现嵌套 $filter

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

我不确定这种方法是否比您的更优化,但可能会有所帮助,

  • $filter 迭代 events 的循环并按 eventType 过滤
  • $let 声明变量events 并存储上述过滤结果
  • 使用点符号$$events.visitorInfo.visitorId 返回visitor 的数组
  • 使用点符号 $$events.visitorInfo.visitorId$setUnion 运算符返回唯一访问者数组 uniquevisitor
db.collection.aggregate([
  { $match: { server: "strong" } },
  {
    $project: {
      total: {
        $let: {
          vars: {
            events: {
              $filter: {
                input: "$events",
                cond: { $eq: ["$$this.eventType", "log"] }
              }
            }
          },
          in: {
            visitor: "$$events.visitorInfo.visitorId",
            uniquevisitor: {
              $setUnion: "$$events.visitorInfo.visitorId"
            }
          }
        }
      }
    }
  }
])

Playground


或没有$let 和两个$project 阶段的类似方法,

db.collection.aggregate([
  { $match: { server: "strong" } },
  {
    $project: {
      events: {
        $filter: {
          input: "$events",
          cond: { $eq: ["$$this.eventType", "log"] }
        }
      }
    }
  },
  {
    $project: {
      total: {
        visitor: "$events.visitorInfo.visitorId",
        uniquevisitor: {
          $setUnion: "$events.visitorInfo.visitorId"
        }
      }
    }
  }
])

Playground

【讨论】:

  • @turvishal 非常感谢!这正是我正在寻找的 $setUnion ...
猜你喜欢
  • 2017-11-05
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 2022-10-07
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
相关资源
最近更新 更多