Mongodb的更新操作符家族里,$currentDate算是一个容易被忽视但特别实用的成员。它的作用很简单:在执行update操作时,自动把某个字段的值设置为当前系统时间。听起来不起眼,但在实际项目中,类似“最后修改时间”、“最后登录时间”这类字段,如果靠应用层代码手动传时间,一旦哪处代码忘了写,数据就会脏掉。把时间交给数据库自己维护,可靠性会高出不少。

$currentDate的基本语法与类型选择
$currentDate的基本用法是把它作为update文档中的一个操作符字段,值可以写成true,也可以写成一个包含$type的对象。写成true时,默认会把字段设置为Date类型;写成对象形式时,可以显式指定类型为date或者timestamp。
两种类型的区别需要搞清楚。date类型对应BSON的Date,就是平时最常见的ISODate格式,精度到毫秒,可读性好,适合绝大多数业务场景。timestamp类型对应BSON的Timestamp,这是MongoDB内部复制的特殊类型,它包含了时间戳和一个递增的计数器,一般不建议在业务数据里使用,除非你明确知道自己在做什么。日常开发中,用得最多的就是date类型。
// 将 lastModified 设置为当前日期(Date类型,等价于 { $currentDate: { lastModified: true } })
db.users.updateOne(
{ _id: 1 },
{
$currentDate: { lastModified: { $type: "date" } }
}
)
// 使用 timestamp 类型
db.users.updateOne(
{ _id: 1 },
{
$currentDate: { loginTime: { $type: "timestamp" } }
}
)注意一个细节:$currentDate只能出现在update操作里,不能用于插入文档的普通insert语句。不过配合upsert选项,它可以在插入新文档时一并生成时间字段,这一点后面会展开讲。另外,如果字段当前不存在,$currentDate会直接创建它,不存在“字段不存在就报错”的问题。
与$set配合使用及upsert场景下的行为
真实的更新语句往往不只是改一个时间字段,通常还要同时修改其他业务字段。$currentDate可以和$set、$inc、$unset等其他更新操作符写在同一个update文档中,各管各的互不干扰。这在实际项目里非常常见,比如更新用户资料的同时刷新最后修改时间。
// 同时更新用户昵称和最后修改时间
db.users.updateOne(
{ _id: 1001 },
{
$set: { nickname: "新昵称", level: 5 },
$currentDate: { lastModified: true }
}
)
// upsert:文档不存在则插入,时间字段一并生成
db.users.updateOne(
{ phone: "13800001111" },
{
$set: { nickname: "张三" },
$currentDate: { createTime: true, updateTime: true }
},
{ upsert: true }
)upsert场景是$currentDate发挥价值的高光时刻。上面第二条语句执行时,如果按phone查不到文档,MongoDB会插入一个新文档,其中createTime和updateTime都会被自动填上当前时间。这样就不用在代码里写if-else判断插入还是更新,一条语句搞定,createTime只在首次创建时有值,updateTime则每次更新都刷新。
还有一个进阶技巧:如果希望更新时字段类型保持Date,同时想避免字段值是字符串或数字导致类型混乱,可以先用$setOnInsert处理只属于创建时刻的字段,再用$currentDate维护更新时间,两者组合能覆盖大部分审计字段需求。唯一要留意的是,同一个字段不能同时出现在$set和$currentDate里,否则会报“Updating the path冲突”的错误。
常见报错排查与方案对比
使用$currentDate时最常见的报错是类型值写错。$type的取值只能是字符串"date"或"timestamp",写成"Date"(首字母大写)或者"datetime"都会直接抛出错误,提示不合法的类型。这个错误在拼接动态查询语句时特别容易踩坑,建议把类型值定义成常量统一引用。
// 错误写法:类型值大小写敏感,必须是小写
db.orders.updateOne(
{ _id: 555 },
{ $currentDate: { payTime: { $type: "Date" } } }
)
// 报错信息示意:The '$type' string field is required to be 'date' or 'timestamp'
// 在应用代码中固化类型常量(Node.js示例)
const UPDATE_TIME = { $type: "date" };
db.collection("orders").updateOne(
{ _id: 555 },
{ $currentDate: { payTime: UPDATE_TIME } }
);再从方案层面对比一下。手动赋值方式即在应用层传new Date()给$set,优点是灵活,可以随意设置过去或未来的时间,也方便做单元测试时固定时间;缺点是依赖代码纪律,多人协作时难免遗漏。$currentDate方式则把责任交给数据库,只要更新语句触发了修改,时间一定会刷新,而且客户端与应用服务器时钟不一致时也不会出错,因为时间取自数据库服务器。
另外要说明的是,如果update操作命中了文档但没有任何字段实际发生变化(比如更新前后值一样),MongoDB 5.0之前的版本可能不会刷新$currentDate字段,这取决于writeConcern和具体版本行为。如果你的业务强依赖“每次提交都刷新时间”,建议在驱动层确认版本行为,或者干脆加一个版本号字段配合$inc递增来保证每次更新都产生真实变更。综合来看,对于created_at、updated_at这类审计字段,$currentDate加上upsert的组合是最省心的方案,值得在项目里推广使用。
MongoDB $currentDateMongoDB更新时间 MongoDB时间戳修改时间:2026-09-13 11:44:30