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 )

当我使用updatefindOneAndUpdate 更新时,无论插入或更新文档,默认模式值createDateupdateDate 总是会更新。当我使用$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 提供和推荐的方法来管理 createdAtupdatedAt。只需将timeStamp: true 作为模式选项传递。

这始终是最佳做法,让您不必担心此类行为。

我使用它,但我从未发现使用 updatefindOneAndUpdate时间戳有问题。

这里是你如何使用它

 new Schema(
   ... //Your schema
 , timestamps: true)

【讨论】:

以上是关于Mongoose upsert 操作是不是更新/更新默认模式值?的主要内容,如果未能解决你的问题,请参考以下文章

(mongoose/promises) 如何检查文档是不是是使用 findOneAndUpdate 和 upsert 创建的

Mongoose upsert 重复键错误

Mongodb/Mongoose bulkwrite(upsert) 性能问题

Mongoose upsert ?????????

带有 upsert 的 Mongoose 重复键错误

带有 upsert 的 Mongoose 重复键错误