假设我有一个类似的集合:
{
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"} }}
])
显然这不起作用,因为“州”字段应该有一个自定义排序,其中有效>过期>无效。那么,可以在聚合中实现自定义排序吗?
或者有更好的方法来做我想在这里做的事情吗?
答案 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
}