首页 > 解决方案 > mongodb group by where 字段不等于 max

问题描述

我想获取所有(按 2 个字段分组)不等于其最大值的文档。

每个文档都有多个版本,因此查看所有最新版本的查询是:

db.getCollection('datatype').aggregate(
   [
     {
       $group:
         {
           _id: {
               "name": "$name",
               "applicationId": "$applicationId"
               },
           latest: { $max: "$version" }
         }
     }
   ]
)

现在我需要这个查询的补充(所有以前的版本,不是最新的)。

我尝试了一些查询,如下所示,但没有一个有效。

db.getCollection('datatype').aggregate(
   [
     {
       $group:
         {
           _id: {
               "name": "$name",
               "applicationId": "$applicationId"
               },
           previousVersions: 
               { $ne: {$max: "$version"} }
               
         }
     }
   ]
)

编辑:输入/输出示例:输入:

db.getCollection('datatype').insertMany([
   { applicationId: "AAAA", name: "foo", version: NumberInt(1) },
   { applicationId: "AAAA", name: "foo", version: NumberInt(2) },
   { applicationId: "AAAA", name: "foo", version: NumberInt(3) },
   { applicationId: "BBBB", name: "foo", version: NumberInt(1) },
   { applicationId: "CCCC", name: "bar", version: NumberInt(1) },
   { applicationId: "CCCC", name: "bar", version: NumberInt(2) }
])

因此,从 applicationId+name 获取最新版本的第一个查询的预期结果是:

{ applicationId: "AAAA", name: "foo", version: NumberInt(3) },
{ applicationId: "BBBB", name: "foo", version: NumberInt(1) },
{ applicationId: "CCCC", name: "bar", version: NumberInt(2) }

我想要的输出基本上是这个查询的补充,除了最新版本之外的所有结果(所有这些文档都有一个更新版本,它们对应的 applicationId+name)

{ applicationId: "AAAA", name: "foo", version: NumberInt(1) },
{ applicationId: "AAAA", name: "foo", version: NumberInt(2) },
{ applicationId: "CCCC", name: "bar", version: NumberInt(1) }

标签: mongodbmongodb-queryaggregation-framework

解决方案


没有单个命令可以执行此操作,如果文档中的自然顺序与顺序db匹配,version并且您没有在其他字段上使用任何可能混淆顺序的特定索引,您可以使用$slice删除不需要的版本,像这样:

db.collection.aggregate([
  {
    $group: {
      _id: {
        "name": "$name",
        "applicationId": "$applicationId"
      },
      not_latest: {
        "$push": "$version"
      }
    }
  },
  {
    $project: {
      _id: 1,
      not_latest: {
        $slice: [
          "$not_latest",
          0,
          {
            $subtract: [
              {
                $size: "$not_latest"
              },
              1
            ]
          }
        ]
      }
    }
  }
])

蒙戈游乐场

如果由于某种原因您不能依赖订单,只需在阶段之前添加一个$sort阶段version: 1$group使用相同的代码。

如果由于某种原因您不想这样做,$sort您可以暂时保存latest并使用它来过滤出最终结果,如下所示:

db.collection.aggregate([
  {
    $group: {
      _id: {
        "name": "$name",
        "applicationId": "$applicationId"
      },
      not_latest: {
        "$push": "$version"
      },
      latest: {
        $max: "$version"
      }
    }
  },
  {
    $project: {
      _id: 1,
      not_latest: {
        $filter: {
          input: "$not_latest",
          as: "elem",
          cond: {
            $ne: [
              "$$elem",
              "$latest"
            ]
          }
        }
      }
    }
  }
])

蒙戈游乐场


推荐阅读