Mongoose upsert操作更新/更新默认架构值吗?

时间:2018-04-16 18:07:39

标签: node.js mongodb mongoose mongoose-schema

Mongoose Schema:

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时(当然我没有传递日期)也是如此。

我似乎没有找到任何可以告诉它是否是预期的行为。除非明确设置,否则我希望仅在插入时添加日期而不更新日期。

2 个答案:

答案 0 :(得分:1)

好吧,我始终建议您使用提供的和推荐的方式通过mongoose管理createdAtupdatedAt。只需将timeStamp: true作为架构选项传递即可。

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

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

以下是您使用它的方式

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

答案 1 :(得分: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字段或映射选项名称(请参阅列表顶部)。当“upsert”实际发生时,此操作仅适用,因此存在且仅与任何“更新”方法匹配的文档从不实际触及此值。

这些运算符是MongoDB如何工作的一部分而不是与mongoose有关,但此处显示的代码显示了猫鼬如何“调整”您的“更新”操作以包含这些额外的操作。

作为参考,schema.js中用于解决当前应用内容的整个主要功能始于Line #798 genUpdates()函数,如此处所示的清单底部所​​示, top部分是该函数的最后几行,其中$setOnInsert的键被定义。

总而言之,每个“更新”操作都是有意的,updatedAt映射字段已分配当前Date值,并且“更新”被修改为包含{{3当作为createdAt映射字段的“upsert”操作的结果创建新文档时,应用的操作。