mongodb 时间戳转日期格式

2,521 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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>, //转换的日期,可以是DateTimestamp(不是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或缺失,则返回的值
    } 
}

相比方案一,少一步管道操作,增加了一些表达式计算,筛选结果也得需要用字符串来匹配