【问题标题】:MongoDB: aggregation, $group by multiple (two) fields, with sorting (receiving latest) resultsMongoDB:聚合,由多个(两个)字段组成的 $group,排序(接收最新)结果
【发布时间】:2020-11-27 20:07:12
【问题描述】:

我正在处理一个非常奇怪的案例,即 Mongo 中的聚合。我有一个非常标准的集合,具有以下架构/字段:

{
  price: Number,
  conneected_realm_id: Number, /** <= destination or warehouse pointer */
  item.id: Number, /** Some kind of SKU */
  last_modified: Number /** Unix timestamp, the latest documents has greater results, always */
}

我的聚合查询,我一直很确定,给我返回了一个 -latest results,但据我现在理解,它实际上没有。

问题:

MongoPlayground example

集合接收实时数据,并将其存储。每个item 和他自己的connected_realm_id 字段(这个仓库/指向的数据)都有自己独特的时间戳。就像这样:

  item: 168652
  in warehouses: 1602 | 1063
  timestamps:  -latest for each
                  7       5
                  4       3 /** <= this are outdated timestamps */
                  2       1 /** <= and so is this */

所以,通过我在 MongoPlayground 中的聚合,我想接收以下数据

All original documents with:
 item: 168652
 groupedBy: { 1602 and 7 }, { 1603 and 5 } /** latest ($max) timestamps for each warehouse */

相反,我会收到每个仓库的每个唯一时间戳,但我不需要它。那么,问题来了:下面的数据能不能实现?

更多信息:

  • Mongo v4.2,所以我可以使用几乎所有运算符,除了$replaceOne
  • 我知道,我可以通过发出 N(仓库计数)请求或通过 .eachAsync 来解决这个问题,但这不是解决方案,因为我有 200 多个仓库。我能够在我的查询中再添加一个阶段(足够长,相信我),但我无法使用{$match: { connected_realm_id: value, last_modified: -latest } } 向 DB 发出 N 请求
  • 集合已经有索引,其中一个是compound by connected_realm_id &amp;&amp; last_modified,所以如果我使用$match.find(),我会收到来自数据库的预排序值。
  • 需要明确的是,这一切都是关于保存/过滤默认的 $$ROOT 文档。所以我不需要接收每个仓库的最新时间戳。我可以通过另一种更有效的方式接收这些数据,重点在于过滤/保存 {data: $$ROOT} 字段

【问题讨论】:

    标签: javascript mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    我想接收以下数据

     item: 168652
     groupedBy: { 1602 and 7 }, { 1603 and 5 }
    
    1. 您需要在最后一个项目分组
    2. 最初您需要在领域分组,然后您需要获取最新的时间戳,即最大值

    play

    db.collection.aggregate([
      {
        $group: {
          _id: {
            connected_realm_id: "$connected_realm_id"
          },
          "data": {
            "$max": "$last_modified"
          },
          "item": {
            "$first": "$item.id"
          }
        }
      },
      {
        $project: {
          "connected_realm_id": "$_id.connected_realm_id",
          "last_modified": "$data",
          "item": 1,
          "_id": 0
        }
      },
      {
        "$group": {
          "_id": "$item",
          "groupedBy": {
            "$push": "$$ROOT"
          }
        }
      }
    ])
    

    编辑:

    this one?

    db.collection.aggregate([
      {
        $group: {
          _id: {
            connected_realm_id: "$connected_realm_id",
            latest_timestamp: {
              $max: "$last_modified"
            },
            
          },
          data: {
            $push: "$$ROOT"
          }
        }
      },
      {
        "$unwind": "$data"
      },
      {
        $group: {
          _id: {
            connected_realm_id: "$data.connected_realm_id"
          },
          "data": {
            "$max": "$data.last_modified"
          },
          "item": {
            "$first": "$data.item.id"
          }
        }
      },
      {
        $project: {
          "connected_realm_id": "$_id.connected_realm_id",
          "last_modified": "$data",
          "item": 1,
          "_id": 0
        }
      },
      {
        "$group": {
          "_id": "$item",
          "groupedBy": {
            "$push": "$$ROOT"
          }
        }
      }
    ])
    

    更新:

    作为从上述编辑派生的 OP,this solves OP's problem

    db.collection.aggregate([
      {
        $group: {
          _id: {
            connected_realm_id: "$connected_realm_id",
            latest_timestamp: {
              $max: "$last_modified"
            },
            
          },
          data: {
            $push: "$$ROOT"
          }
        }
      },
      {
        "$unwind": "$data"
      },
      {
        $group: {
          _id: {
            connected_realm_id: "$data.connected_realm_id"
          },
          "data": {
            "$max": "$data.last_modified"
          },
          "item": {
            "$push": "$data"
          }
        }
      }
    ])
    

    【讨论】:

    • 我正在检查它,这一切都是关于保存/过滤默认 $$ROOT 文档。所以为了清楚起见,我不需要接收每个仓库的最新时间戳。我需要filter 数据。
    • 你这是什么意思?你运行查询的时间,你不会有时间戳?
    • 看看我在playground的例子,重点是过滤文档,就像在{data: $$ROOT}字段中一样,没有收到每个仓库的最新时间戳的不同值。
    • kind of this ?我还是不明白
    • 没有。看看这个data set example。左栏中的文档,代表我需要接收的数据。对于每个connected_realm_id 都有自己的最大timestamp 字段,文档在data 字段中。另一种说法:$$ROOT 文档filtereredBy/groupedBy: connected_realm_id and max(last_modified)
    【解决方案2】:

    MongoPlayground的正确(最终解决方案)

    数据集:

    [
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 1596719280
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 1596719280
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 1596719280
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 1596719280
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 2
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 3
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 4
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 5
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 1596719280
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1602,
        last_modified: 1596719280
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 1596719267
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 1596719267
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 1596719267
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 1596719267
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 1
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 2
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 3
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 4
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 5
      },
      {
        item: {
          id: 168652
        },
        connected_realm_id: 1603,
        last_modified: 1596719267
      }
    ]
    

    聚合查询

    db.collection.aggregate([
      {
        $group: {
          _id: {
            connected_realm_id: "$connected_realm_id"
          },
          latest: {
            $max: "$last_modified"
          },
          data: {
            $push: "$$ROOT"
          }
        }
      },
      {
        $unwind: "$data"
      },
      {
        $addFields: {
          "data.latest": {
            $cond: {
              if: {
                $eq: [
                  "$data.last_modified",
                  "$latest"
                ]
              },
              then: "$latest",
              else: "$false"
            }
          }
        }
      },
      {
        "$replaceRoot": {
          "newRoot": "$data"
        }
      },
      {
        "$match": {
          "latest": {
            "$exists": true,
            "$ne": null
          }
        }
      }
    ])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-28
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 1970-01-01
      • 2021-06-26
      • 2019-01-30
      相关资源
      最近更新 更多