首页 > 解决方案 > 当一个数组元素出现在另一个元素之前时匹配(MongoDb)

问题描述

我收藏中的文件我的订单结构如下:

[
{
  OrderId: 'ID1',
  StatusLog: [
    {
      Timestamp: 'Some ISO Date',
      Status: 1,
      Reason: 'Because',
      User: 'User1'
    },
    {
      Timestamp: 'Some ISO Date',
      Status: 2,
      Reason: 'No Idea',
      User: 'User2'
    },
    {
      Timestamp: 'Some ISO Date',
      Status: 3,
      Reason: 'Because',
      User: 'User2'
    },
    {
      Timestamp: 'Some ISO Date',
      Status: 2 // NOTE: status can go back to 2,
      Reason: 'Some Idea',
      User: 'User1'
    }
},
{
  OrderId: 'ID2',
  StatusLog: [
    {
      Timestamp: 'Some ISO Date',
      Status: 1,
      Reason: 'Because',
      User: 'User1'
    },
    {
      Timestamp: 'Some ISO Date',
      Status: 2, 
      Reason: 'The reason to include in results',
      User: 'User2'
    },
    {
      Timestamp: 'Some ISO Date',
      Status: 3, 
      Reason: 'Because',
      User: 'User2'
    }
}
]

我编写了一个聚合查询,可以让我计算每个原因+用户组合的订单数量。

    [
        {
            $unwind: {
                path: '$StatusLog'
            }
        },

        {
            $match: {
                'StatusLog.Status': 2
            }
        },

        {
            $group: {
                _id: {
                    'reason': '$StatusLog.Reason',
                    'user': '$StatusLog.User'
                },
                'orderCount': { $sum: 1 }
            }
        },
    ]

上述查询的输出是我需要的确切格式。但是,我希望将这些过滤器添加到查询中:

  1. 订单必须包含 StatusLog 元素,Status=2
  2. 订单必须包含之前的StatusLog 元素,Status=3
  3. 每个订单只能计算一次

因此,从上面的示例数据数组中,只有 OrderId='ID1' 的订单,结果应该是:

[
{ 
    "_id" : {
        "reason" : "The reason to include in results", 
        "user" : "User2"
    }, 
    "orderCount" : 1.0
}
]

任何帮助,将不胜感激。

标签: mongodbmongodb-queryaggregation-framework

解决方案


  • $unwind解构StatusLog数组
  • $match2 或 3 中的状态
  • $group按用户并制作数组Status,获取第一个原因并orderCount获取Status2
  • $match使用过滤器在 2 和 3 中具有状态的用户$all
db.collection.aggregate([
  { $unwind: "$StatusLog" },
  { $match: { "StatusLog.Status": { $in: [2, 3] } } },
  {
    $group: {
      _id: "$StatusLog.User",
      Status: { $push: "$StatusLog.Status" },
      Reason: { $first: "$StatusLog.Reason" },
      orderCount: {
        $sum: { $cond: [{ $eq: ["$StatusLog.Status", 2] }, 1, 0] }
      }
    }
  },
  { $match: { Status: { $all: [2, 3] } } }
])

操场


推荐阅读