持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情
问题
近期新接手了一个项目,然后发现有些用户由于一些特殊原因,在生日当天,积分没有发放成功,现在需要给这些用户补发积分,目前对这些积分任务的补发是没有重试机制。所以我需要手动查找。
查找的过程中发现,生日信息存储在mongodb ,日期类型使用的是时间戳(单位:毫秒)。积分发放代码,发现是查询出birthday 字段不为空的用户,然后再代码中根据日期进行筛选。
优化方案
我们只需要查询出来当天的用户就可以,没有必要查询多余的数据。
方案一
db.t_community_user_821219656227868672.aggregate([{
$project: {
_id: 0,
birthday: 1,
birthdayDate: {
$add: [
ISODate('1970-01-01T00:00:00.000Z'),
'$birthday'
]
}
}
}, {
$project: {
birthday: 1,
birthdayDate: 1,
br: 1,
month: {
$month: '$birthdayDate'
},
day: {
$dayOfMonth: '$birthdayDate'
}
}
}])
使用$project来将我们控制我们需要的字段数据列,并且我们可以在原有的基础上进行运算
$project
控制字段数据列,并可以添加表达式进行计算,
使用规则:
- 普通列:
{<field>: <1 or true>}表示要显示的内容,没有使用此字段展示自动移除 _id:_id: <0 or false>排除_id字段,移除其他字段,禁止使用此方法- 表达式:
<field>: <expression>可以添加新字段或重置现有字段,并附加表达式
$add
将数字相加获奖数字和日期相加。如果其中一个参数是日期的,则将其他参数视为毫秒以相加日期。
使用规则:
{ $add: [ <expression1>, <expression2>, ... ] }
参数可以是任何有效的表达式,只要它们解析为所有数字或数字和日期。
我们根据查询结果直接筛选具体某月某天就可以了
$month
1-12月
使用规则:
{
date: <dateExpression>, //转换的日期,可以是Date、Timestamp(不是int64)、ObjectId
timezone: <tzExpression> //可选 时区
}
$dayOfMonth
返回某个月的具体多少天,1-31
使用规则同$month,还有很多类似的方法$year、$hour等
方案二
db.users.aggregate([{
$project: {
_id: 0,
birthday: 1,
birthdayDate: {
$add: [
ISODate('1970-01-01T00:00:00.000Z'),
'$birthday'
]
},
month: {
$dateToString: {
format: '%m',
date: {
$add: [
ISODate('1970-01-01T00:00:00.000Z'),
'$birthday'
]
},
timezone: '+08:00'
}
},
day: {
$dateToString: {
format: '%d',
date: {
$add: [
ISODate('1970-01-01T00:00:00.000Z'),
'$birthday'
]
},
timezone: '+08:00'
}
}
}
}])
$dateToString
将日期格式转换为字符串 使用规则:
{
$dateToString: {
date: <dateExpression>, //需要转换的日期,可以是Date、Timestamp(不是int64)、ObjectId
format: <formatString>, //可选,日期格式字符串,默认"%Y-%m-%dT%H:%M:%S.%LZ"
timezone: <tzExpression>, //时区,"GMT"、"+08:00"
onNull: <expression> //可选的,如果为null或缺失,则返回的值
}
}
相比方案一,少一步管道操作,增加了一些表达式计算,筛选结果也得需要用字符串来匹配