在 mongodb 中使用组查找

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

我在mongodb上有一堆这种格式的记录

[
  {_id: 1, date:'2023-07-28',sales:1,ad_id:1,status: 'Active'},
  {_id: 2 , date:'2023-07-29',sales:2,ad_id:1,status: 'Active'},
   {_id: 3, date: '2023-07-30',sales: 4,ad_id:1,status: 'Paused'},
   {_id: 4, date: '2023-07-30',sales: 4,ad_id:2,status: 'Paused'},

]

现在,如果我想要从日期

2023-07-28
2023-07-29
的数据。我想要对销售额进行求和,但我想要最新记录的状态,即
2023-07-30
。所以最后我想要的结果是这样的
{'ad_id': 1, sales: 3, status: 'Paused'}

在 mysql 上会是这样的

 with ad as (
 SELECT sum(sales) as totalSales,ad_id from table_name
    where date >= '2023-07-28' and date <= '2023-07-29'
 group by ad_id 
)
SELECT * from ad left join (
   SELECT id,ad_id,status from table_name where id in (
       select max(id) from table_name group by ad_id
   )
) t on t.ad_id = ad.ad_id

mongodb aggregation-framework
2个回答
2
投票

这是您可以做到的一种方法。

db.collection.aggregate([
  {
    "$group": {
      "_id": "$ad_id",
      "statusObj": {
        // get the last status
        "$max": {
          "date": "$date",
          "_id": "$_id",
          "status": "$status"
        }
      },
      "sales": {
        "$sum": {
          // only sum sales in date range
          "$cond": [
            {"$and": [
                {"$gte": ["$date", "2023-07-28"]},
                {"$lte": ["$date", "2023-07-29"]}
              ]
            },
            "$sales",
            0
          ]
        }
      }
    }
  },
  { // output desired fields
    "$project": {
      "_id": 0,
      "ad_id": "$_id",
      "sales": 1,
      "status": "$statusObj.status"
    }
  }
])

mongoplayground.net 上尝试一下。


1
投票

我将总结以下代码的作用:

  1. 使用
    facet
    创建两个差异聚合,分别命名为
    salesSum
    recentStatus
  2. salesSum
    中,我们筛选日期,然后对
    ad_id
    列进行分组,然后从中提取
    sales
    信息
  3. recentStatus
    中,我们对
    ad_id
    进行分组,并通过分组计算出
    _id
    列的最大值,然后在
    maxId
    上对其进行过滤,以使用
    status
     获取最近的 
    $push: "$$ROOT"
  4. 然后使用
    salesSum
    recentStatus
    $unwind
  5. 表上做一种笛卡尔积
  6. 然后在
    ad_id
  7. 上过滤它们

代码:

db.collection.aggregate([
  {
    $facet: {
      salesSum: [
        {
          // filters on date
          $match: {
            date: {
              $gte: "2023-07-28",
              $lte: "2023-07-29",
              
            },
            
          },
          
        },
        {
          // groups on ad_id and gets sum of sales
          $group: {
            _id: "$ad_id",
            sales: {
              $sum: "$sales",
              
            },
            
          },
          
        },
        {
          // select specific cols
          $project: {
            _id: 0,
            ad_id: "$_id",
            sales: 1,
            
          },
          
        },
        
      ],
      recentStatus: [
        {
          // group on ad_id, get maxId
          // assuming maximum ID is associated with latest entry
          $group: {
            _id: "$ad_id",
            maxId: {
              $max: "$_id",
              
            },
            // pushes all related data which have ad_id values as the same as grouped value
            items: {
              $push: "$$ROOT",
              
            },
            
          },
          
        },
        {
          $unwind: "$items",
          
        },
        {
          // filter items based on maxId
          $match: {
            $expr: {
              $eq: [
                "$maxId",
                "$items._id"
              ],
              
            },
            
          },
          
        },
        {
          $project: {
            _id: 0,
            ad_id: "$_id",
            status: "$items.status",
            
          },
          
        },
        
      ],
      
    },
    
  },
  {
    $unwind: "$salesSum",
    
  },
  {
    $unwind: "$recentStatus",
    
  },
  {
    $match: {
      $expr: {
        $eq: [
          "$salesSum.ad_id",
          "$recentStatus.ad_id"
        ],
        
      },
      
    },
    
  },
  {
    $project: {
      ad_id: "$salesSum.ad_id",
      sales: "$salesSum.sales",
      status: "$recentStatus.status",
      
    },
    
  },
  
])

在 Mongo PlayGround 上尝试一下

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