Mongodb-将文档分组并从每个组中获取具有字段最大值的文档

时间:2019-10-23 15:32:45

标签: mongodb aggregation-framework

我有一个Mongo集合,其中的文档从未更新,而是读取了最新文档,并插入了一个新文档,其中某些字段已更新。这些通用文档共享一个标识符document_identifier,以将它们与其他文档区分开。

我想执行以下查询: 获取所有customer_id为X的文档,将其按document_identifier分组,然后从每个组中取出带有最大updated_at时间戳的文档。它应该完整返回文档(所有属性)。

示例数据集:

{
    document_identifier: "abc",
    updated_at: 1000,
    customer_id: "123",
    ...  
},

{
    document_identifier: "def",
    updated_at: 1001,
    customer_id: "123",
    ...
},

{
    document_identifier: "abc",
    updated_at: 1002,
    customer_id: "123",
    ...
},

{
    document_identifier: "def",
    updated_at: 10003,
    customer_id: "123",
    ...
},

{
    document_identifier: "xyz",
    updated_at: 1004,
    customer_id: "999",
    ...
},

{
    document_identifier: "abc",
    updated_at: 1005,
    customer_id: "123",
    ...
},

{
    document_identifier: "def",
    updated_at: 1006,
    customer_id: "123",
    ...
},

在上面的示例中,如果我要查询“ 123”的customer_id,结果将是:

{
    document_identifier: "abc",
    updated_at: 1005,
    customer_id: "123",
    ...
},

{
    document_identifier: "def",
    updated_at: 1006,
    customer_id: "123",
    ...
},

我已经转向Mongo聚合框架,但似乎无法理解。

非常感谢您的帮助。

编辑:这是我现在所拥有的,它似乎正在工作,但是我不确定这是最佳的:

db.my_colleciton.aggregate([
    {
       $match: {customer_id: <value to query on>}
    },

    {
        $sort: {updated_at: -1}
    },

    {
        $group: {
            _id: "$document_identifier",
            my_doc: {$first: "$$ROOT"}
        }
    },

    {
        "$replaceRoot": {newRoot: "$my_doc"}
    }
])

2 个答案:

答案 0 :(得分:0)

因此,如果我理解正确,我认为此查询可能会有所帮助...

db.records.aggregate(
[
    { $group: {
        _id: {customer_id: "$customer_id", document_identifier: "$document_identifier"},
        max_updated_at: { $max:  "$updated_at" }
    }}
])

想法是将两个字段customer_iddocument_identifier分组。对于该组合​​,请显示最大updated_at,该数字应为滚动整数。

对于您提供的结果显示的数据集...

{ "_id" : { "customer_id" : "123", "document_identifier" : "def" }, "max_updated_at" : 10003 }
{ "_id" : { "customer_id" : "999", "document_identifier" : "xyz" }, "max_updated_at" : 1004 }
{ "_id" : { "customer_id" : "123", "document_identifier" : "abc" }, "max_updated_at" : 1005 }

输出的格式与您的示例不同。可以,还是您需要输出的格式来匹配示例?

编辑: 因此,OP请求输出的格式与问题中描述的预期格式匹配。事不宜迟...

db.records.aggregate(
[
    { $group: {
        _id: {customer_id: "$customer_id", document_identifier: "$document_identifier"},
        max_updated_at: { $max:  "$updated_at" }
    }},
    { $project: {
        _id: 0,
        document_identifier: "$_id.document_identifier",
        updated_at: "$max_updated_at",
        customer_id: "$_id.customer_id"

    }}
]
)

现在输出如下:

{ "document_identifier" : "def", "updated_at" : 10003, "customer_id" : "123" }
{ "document_identifier" : "xyz", "updated_at" : 1004, "customer_id" : "999" }
{ "document_identifier" : "abc", "updated_at" : 1005, "customer_id" : "123" }

编辑编号2:

好,因此OP具有比问题中所代表的更多的字段,并且希望查看所有用于匹配文档的字段。这是到目前为止的查询...

db.records.aggregate(
[
    { $match: { customer_id: "123" }},
    { $group: {
        _id: {customer_id: "$customer_id", document_identifier: "$document_identifier"},
        max_updated_at: { $max:  "$updated_at" }
    }},
    { $lookup: {
        from: "records",
        let: {
          customer_id: "$_id.customer_id",
          document_identifier: "$_id.document_identifier",
          max_updated_at: "$max_updated_at"
        },
        pipeline: [
          {
            $match: {
              $expr: {
                $and: [
                  { $eq: [ "$customer_id", "$$customer_id"] },
                  { $eq: [ "$document_identifier", "$$document_identifier"] },
                  { $eq: [ "$updated_at", "$$max_updated_at"] }
                ]
              }
            }
          }
        ],
        as: "result"
    }},
    { $unwind: "$result" } ,
    { $replaceRoot: { newRoot: "$result" } }
]
)

现在,这首先匹配客户ID。然后,它使用$ lookup和$ replaceRoot进行自我联接,以仅显示原始文档。不管存在多少字段,这都会保留原始文档格式。

输出:

{ "_id" : ObjectId("5db07a5d3cf0c979dd020f85"), "document_identifier" : "def", "updated_at" : 10003, "customer_id" : "123" }
{ "_id" : ObjectId("5db07a5d3cf0c979dd020f87"), "document_identifier" : "abc", "updated_at" : 1005, "customer_id" : "123" }

答案 1 :(得分:0)

首先按updated_at降序排序 ,然后按document_identifier依次$group排序,然后通过$first为该特定组选择第一个文档。

并保留与 $first 相同的字段。

查询: Demo Link

db.collection.aggregate([
    { $sort: { updated_at: -1 } },
    {
      $group: {
        _id: "$document_identifier",
        document_identifier: { $first: "$document_identifier" },
        updated_at: { $first: "$updated_at" },
        customer_id: { $first: "$customer_id" }
      }
    }
  ]).pretty();

结果:

{
    "_id" : "abc",
    "document_identifier" : "abc",
    "updated_at" : 1005,
    "customer_id" : "123"
},
{
    "_id" : "xyz",
    "document_identifier" : "xyz",
    "updated_at" : 1004,
    "customer_id" : "999"
},
{
    "_id" : "def",
    "document_identifier" : "def",
    "updated_at" : 10003,
    "customer_id" : "123"
}