【问题标题】:MongoDB: Sort in combination with Aggregation groupMongoDB:结合聚合组排序
【发布时间】:2015-12-28 03:40:26
【问题描述】:

我有一个名为 transaction 的集合,其中包含以下文档,

/* 0 */
{
    "_id" : ObjectId("5603fad216e90d53d6795131"),
    "statusId" : "65c719e6727d",
    "relatedWith" : "65c719e67267",
    "status" : "A",
    "userId" : "100",
    "createdTs" : ISODate("2015-09-24T13:15:36.609Z")
}

/* 1 */
{
    "_id" : ObjectId("5603fad216e90d53d6795134"),
    "statusId" : "65c719e6727d",
    "relatedWith" : "65c719e6726d",
    "status" : "B",
    "userId" : "100",
    "createdTs" : ISODate("2015-09-24T13:14:31.609Z")
}

/* 2 */
{
    "_id" : ObjectId("5603fad216e90d53d679512e"),
    "statusId" : "65c719e6727d",
    "relatedWith" : "65c719e6726d",
    "status" : "C",
    "userId" : "100",
    "createdTs" : ISODate("2015-09-24T13:13:36.609Z")
}

/* 3 */
{
    "_id" : ObjectId("5603fad216e90d53d6795132"),
    "statusId" : "65c719e6727d",
    "relatedWith" : "65c719e6726d",
    "status" : "D",
    "userId" : "100",
    "createdTs" : ISODate("2015-09-24T13:16:36.609Z")
}

当我在没有$group 的情况下运行以下Aggregation 查询时,

db.transaction.aggregate([
    {
        "$match": {
            "userId": "100",
            "statusId": "65c719e6727d"
        }
    },
    {
        "$sort": {
            "createdTs": -1
        }
    }
])

我以预期的排序顺序得到结果。即 按降序对 createdT 进行排序(最小结果)

/* 0 */
{
    "result" : [ 
        {
            "_id" : ObjectId("5603fad216e90d53d6795132"),
            "createdTs" : ISODate("2015-09-24T13:16:36.609Z")
        }, 
        {
            "_id" : ObjectId("5603fad216e90d53d6795131"),
            "createdTs" : ISODate("2015-09-24T13:15:36.609Z")
        }, 
        {
            "_id" : ObjectId("5603fad216e90d53d6795134"),
            "createdTs" : ISODate("2015-09-24T13:14:31.609Z")
        }, 
        {
            "_id" : ObjectId("5603fad216e90d53d679512e"),
            "createdTs" : ISODate("2015-09-24T13:13:36.609Z")
        }
    ],
    "ok" : 1
}

如果我使用$group 应用以​​下聚合,则结果是逆排序的(即升序排序)

db.transaction.aggregate([
    {
        "$match": {
            "userId": "100",
            "statusId": "65c719e6727d"
        }
    },
    {
        "$sort": {
            "createdTs": -1
        }
    },
    {
        $group: {
                "_id": {
                    "statusId": "$statusId",
                    "relatedWith": "$relatedWith",
                    "status": "$status"
                },
                "status": {$first: "$status"}, 
                "statusId": {$first: "$statusId"},
                "relatedWith": {$first: "$relatedWith"},
                "createdTs": {$first: "$createdTs"}
        }
    }
]);

我以相反的顺序得到结果,即**按升序对 createdT 进行排序**

/* 0 */
{
    "result" : [ 
        {
            "_id" : ObjectId("5603fad216e90d53d679512e"),
            "createdTs" : ISODate("2015-09-24T13:13:36.609Z")
        }, 
        {
            "_id" : ObjectId("5603fad216e90d53d6795134"),
            "createdTs" : ISODate("2015-09-24T13:14:31.609Z")
        }, 
        {
            "_id" : ObjectId("5603fad216e90d53d6795131"),
            "createdTs" : ISODate("2015-09-24T13:15:36.609Z")
        }, 
        {
            "_id" : ObjectId("5603fad216e90d53d6795132"),
            "createdTs" : ISODate("2015-09-24T13:16:36.609Z")
        }
    ],
    "ok" : 1
}

我哪里错了?

【问题讨论】:

  • 你能用 "createdTs": 1 试试吗

标签: mongodb sorting


【解决方案1】:

你没有做错什么,它是 Mongodb 中的 $group 行为

让我们看看这个例子

假设您在集合中有以下文档

{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }
{ "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }
{ "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") }
{ "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-15T12:05:10Z") }
{ "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T14:12:12Z") }

现在如果你运行这个

db.collection.aggregate([{ $sort: { item: 1,date:1}} ] )

输出将按项目和日期的升序排列。

现在,如果您在聚合管道中添加组阶段,它将反转顺序。

db.collection.aggregate([{ $sort: { item: 1,date:1}},{$group:{_id:"$item"}} ] ) 

输出将是

{ "_id" : "xyz" }
{ "_id" : "jkl" }
{ "_id" : "abc" }

现在解决您的问题

将 "createdTs": -1 更改为 "createdTs": 1 for group

【讨论】:

  • MongoDB 文档说 $group 确保任何订单。此解决方案在未来的版本中可能不起作用,而且除了使查询看起来错误之外有点危险,因为现在它看起来与您真正打算做的相反。
【解决方案2】:

$group 阶段不保证结果的顺序。见here第一段。 如果您希望结果在 $group 之后排序,则需要在 $group 阶段之后添加 $sort

在您的情况下,您应该将 $sort 移到 $group 之后并且在您提出问题之前:不,$sort 将无法像在 $group 之前那样使用索引$group :-).

$group 的内部算法似乎保持某种排序(显然是颠倒的),但我不会指望它并添加一个 $sort。

【讨论】:

    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 2019-01-14
    • 1970-01-01
    相关资源
    最近更新 更多