$filter inside $reduce 或 inside $map from array without unwind

$filter inside $reduce or inside $map from array without unwind

我需要一些帮助: 我想优化此查询使其更快,它需要通过 events.eventType:"log" 所有带有 server:"strong" 的文档进行过滤,但没有单独的展开和过滤阶段,可能以某种方式在 $reduce 阶段内添加$过滤器。

单个文档示例:

 {
 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 如何实现?

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

  • $filter 迭代 events 的循环并按 eventType
  • 过滤
  • $let声明一个变量events并存储上面的过滤结果
  • return visitor 的数组,使用圆点表示法 $$events.visitorInfo.visitorId
  • return 唯一身份访问者数组 uniquevisitor 通过使用点符号 $$events.visitorInfo.visitorId$setUnion 运算符
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