$filter 位于数组中的 $reduce 内或 $map 内,无需展开

问题描述 投票:0回答:2

我需要一些帮助: 我想优化这个查询更快,它需要通过 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"
  ]
}

} ]

游乐场

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

mongodb mongodb-query aggregation-framework
2个回答
1
投票

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

  • $filter
    迭代
    events
    的循环并按
    eventType
  • 进行过滤
  • $let
    声明变量
    events
    并存储上述过滤结果
  • 使用点表示法返回
    visitor
    的数组
    $$events.visitorInfo.visitorId
  • 使用点表示法
    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"
            }
          }
        }
      }
    }
  }
])

游乐场


或没有

$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"
        }
      }
    }
  }
])

游乐场


0
投票

您可以直接使用过滤后的事件作为输入来减少阶段。例如就我而言,我有一系列优惠 - 其中一些是特殊用户的。我想在拥有有效用户的用户中找到最好的。这是我在 $project 中所做的:

  bestOffer: {
$reduce: {
  input: {$filter: {
input: '$offers', as: 'offer',
cond: {$gt: ['$$offer.rfqUser',{}]}
}},
  initialValue: {'yield': 0},
  in: {
    $cond: [              {
      '$gte': ['$$this.yield', '$$value.yield']},
      '$$this', '$$value'
    ]
  }
}

},

© www.soinside.com 2019 - 2024. All rights reserved.