首先进行分组,排序和选择

时间:2015-10-29 19:36:43

标签: mongodb aggregation-framework database nosql

假设我有一个类似的集合:

{
  couponId: "abc",
  state: "valid",
  date: "2015-11-01"
}
{
  couponId: "abc",
  state: "expired",
  date: "2015-10-01"
}
{
  couponId: "abc",
  state: "invalid",
  date: "2015-09-01"
}
{
  couponId: "xyz",
  state: "invalid",
  date: "2015-11-01"
}
{
  couponId: "xyz",
  state: "expired",
  date: "2015-10-01"
}
{
  couponId: "xyz",
  state: "expired",
  date: "2015-09-01"
}
...

优惠券可以有效/无效/已过期。 现在,我想获取优惠券列表,其中每张优惠券都是根据以下逻辑选择的:

  • 如果存在“有效”优惠券,请使用
  • 如果存在“过期”优惠券,请使用
  • 否则获得“无效”优惠券。

将此逻辑应用于上面的列表应该产生:

    {
      couponId: "abc", /* for "abc" "valid" exists */
      state: "valid",
      date: "2015-11-01"
    },
    {
      couponId: "xyz", /* for "xyz" "valid" does not exist, use the next best "expired" */
      state: "expired",
      date: "2015-11-01"
    }

基本上,有效>已过期>无效

我想过使用聚合操作,尝试模拟SQL groupby + sort + selectFirst,

db.xyz.aggregate([
  {$sort : { couponId: 1, state: -1 } },
  {$group : { _id : "$couponId", document: {$first : "$$ROOT"} }}
])

显然这不起作用,因为“州”字段应该有一个自定义排序,其中有效>过期>无效。那么,可以在聚合中实现自定义排序吗?

或者有更好的方法来做我想在这里做的事情吗?

1 个答案:

答案 0 :(得分:1)

一个更好的方法,虽然不是那么干净/漂亮(对我来说似乎有些惹人注意:P),是在你的上面标准/逻辑中嵌入一些 $cond 运算符表达式 $group 管道阶段。最好通过运行以下聚合管道来解释:

db.xyz.aggregate([
    {
        "$group": {
            "_id": "$couponId",
            "state": {
                "$first": {
                    "$cond": [
                        { "$eq": ["$state", "valid"]},
                        "$state",
                        {
                           "$cond": [
                                { "$eq": ["$state", "invalid"]},
                                "$state",
                                "expired"
                            ]
                        }
                    ]
                }
            },
            "date": {
                "$first": {
                    "$cond": [
                        { "$eq": ["$state", "valid"]},
                        "$date",
                        {
                           "$cond": [
                                { "$eq": ["$state", "invalid"]},
                                "$date",
                                {
                                   "$cond": [
                                        { "$eq": ["$state", "expired"]},
                                        "$date", 
                                        "1970-01-01"
                                    ]
                                }
                            ]
                        }
                    ]
                }
            }
        }
    }
])

示例输出

/* 0 */
{
    "result" : [ 
        {
            "_id" : "xyz",
            "state" : "invalid",
            "date" : "2015-11-01"
        }, 
        {
            "_id" : "abc",
            "state" : "valid",
            "date" : "2015-11-01"
        }
    ],
    "ok" : 1
}
相关问题