Mongoose upsert 操作是不是更新/更新默认模式值?
Posted
技术标签:
【中文标题】Mongoose upsert 操作是不是更新/更新默认模式值?【英文标题】:Does Mongoose upsert operation update/renew default schema values?Mongoose upsert 操作是否更新/更新默认模式值? 【发布时间】:2018-09-26 13:40:01 【问题描述】:Mongoose 架构:
new Schema(
...
createDate: type: Date, default: Date.now ,
updateDate: type: Date, default: Date.now
);
Upsert 操作:
const upsertDoc =
...
Model.update( key: 123 , upsertDoc, upsert: true )
当我使用update
或findOneAndUpdate
更新时,无论插入或更新文档,默认模式值createDate
和updateDate
总是会更新。当我使用$set
时也是如此(当然我不会通过日期)。
我似乎没有找到任何可以判断这是否是预期行为的信息。我希望日期仅在插入时添加而不是更新,除非明确设置。
【问题讨论】:
嗨 Talha Awan - 我可以请你澄清一些事情吗?您在架构中使用timestamps option 吗? @VinceBowdren,不。 【参考方案1】:如果您正在寻找预期行为的“证据”,那么只需查看源代码本身即可。特别是schema.js
main definition内:
updates.$setOnInsert = ;
updates.$setOnInsert[createdAt] = now;
return updates;
;
this.methods.initializeTimestamps = function()
if (createdAt && !this.get(createdAt))
this.set(createdAt, new Date());
if (updatedAt && !this.get(updatedAt))
this.set(updatedAt, new Date());
return this;
;
this.pre('findOneAndUpdate', _setTimestampsOnUpdate);
this.pre('update', _setTimestampsOnUpdate);
this.pre('updateOne', _setTimestampsOnUpdate);
this.pre('updateMany', _setTimestampsOnUpdate);
function _setTimestampsOnUpdate(next)
var overwrite = this.options.overwrite;
this.update(, genUpdates(this.getUpdate(), overwrite),
overwrite: overwrite
);
applyTimestampsToChildren(this);
next();
因此,您可以看到所有'pre'
中间件处理程序正在为每个“更新”方法变体和相同的功能代码注册。这些都实质上修改了您发出的任何“更新”中的$set
运算符,以包含updatedAt
字段,或者您在架构选项中映射到该键的任何名称。
使用“upsert”操作发送的实际语句使用$setOnInsert
作为createdAt
字段或映射的选项名称(参见清单顶部)。此操作仅在“更新插入”实际发生时适用,因此存在的文档仅与任何“更新”方法相匹配,该值从不实际触及。
这些操作符是 MongoDB 工作方式的一部分,与 mongoose 无关,但此处显示的代码显示了 mongoose 如何“调整”您的“更新”操作以包含这些额外操作。
作为参考 schema.js
中的整个 main 函数,它计算出当前应用的内容从 Line #798 开始,用于 genUpdates()
函数,在此处显示的清单底部调用,但顶部是最后几个该函数的行,其中$setOnInsert
的键被定义。
因此,总而言之,是的,每个“更新”操作都是有意为 updatedAt
映射字段分配了当前的 Date
值,并且“更新”被修改为包含 $setOnInsert
操作 仅适用于由于 createdAt
映射字段的“更新插入”操作而创建新文档时。
【讨论】:
一如既往的彻底和深入的回答。谢谢! 嗨,尼尔;我可能误解了,但看起来您描述的代码与timestamps option 有关,但问题是关于defaults,它们的操作方式不同 - 对吗? @VinceBowdren 我认为这里的重点是了解$set
和$setOnInsert
之间的区别。相信“猫鼬魔法”是那种让 OP 和许多其他人陷入各种麻烦的事情,因为他们不明白这个“简单的选项设置”实际上做了什么。如果您花时间向人们解释它,那么他们实际上可能会理解“为什么”这样做。此外,OP 只花了 100 代表。应该得到比 RTFM 更好的响应吗?【参考方案2】:
好吧,我总是建议使用 mongoose 提供和推荐的方法来管理 createdAt
和 updatedAt
。只需将timeStamp: true
作为模式选项传递。
这始终是最佳做法,让您不必担心此类行为。
我使用它,但我从未发现使用 update
或 findOneAndUpdate
的时间戳有问题。
这里是你如何使用它
new Schema(
... //Your schema
, timestamps: true)
【讨论】:
以上是关于Mongoose upsert 操作是不是更新/更新默认模式值?的主要内容,如果未能解决你的问题,请参考以下文章
(mongoose/promises) 如何检查文档是不是是使用 findOneAndUpdate 和 upsert 创建的