225

有没有办法将 created_at 和updated_at字段添加到猫鼬模式中,而不必在每次MyModel()调用 new 时都传递它们?

created_at字段将是一个日期,并且仅在创建文档时添加。每当在文档上调用该updated_at字段时,都会使用新日期更新该字段。save()

我已经在我的架构中尝试过这个,但是除非我明确添加它,否则该字段不会显示:

var ItemSchema = new Schema({
    name    : { type: String, required: true, trim: true },
    created_at    : { type: Date, required: true, default: Date.now }
});
4

22 回答 22

289

更新:(5年后)

注意:如果您决定使用Kappa 架构事件溯源 + CQRS),那么您根本不需要更新日期。由于您的数据是不可变的、仅追加的事件日志,因此您只需要事件创建日期。类似于Lambda 架构,如下所述。那么您的应用程序状态是事件日志(派生数据)的投影。如果您收到有关现有实体的后续事件,那么您将使用该事件的创建日期作为您的实体的更新日期。这是miceroservice系统中常用的(并且通常被误解)的做法。

更新:(4年后)

如果您使用ObjectId作为您的_id字段(通常是这种情况),那么您需要做的就是:

let document = {
  updatedAt: new Date(),
}

在下面查看我的原始答案,了解如何从_id字段中获取创建的时间戳。如果您需要使用来自外部系统的 ID,请查看 Roman Rhrn Nesterov 的答案。

更新:(2.5年后)

您现在可以在mongoose版本 >= 4.0的情况下使用#timestamps选项。

let ItemSchema = new Schema({
  name: { type: String, required: true, trim: true }
},
{
  timestamps: true
});

如果为您的架构设置时间戳、mongoose 分配createdAtupdatedAt字段,则分配的类型为Date.

您还可以指定时间戳文件的名称:

timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }

注意:如果您正在处理具有关键数据的大型应用程序,您应该重新考虑更新您的文档。我建议您使用不可变的、仅附加的数据(lambda 架构)。这意味着您只允许插入。不允许更新和删除!如果您想“删除”一条记录,您可以轻松地插入带有一些timestamp/字段的文档的新版本,version 然后将deleted字段设置为true. 类似地,如果您想更新一个文档 - 您创建一个新的文档,其中更新了相应的字段并复制了其余字段。然后为了查询此文档,您将获得具有最新时间戳或最高版本的文档,即没有“删除”(deleted字段未定义或为假`)。

数据不变性确保您的数据是可调试的——您可以跟踪每个文档的历史记录。如果出现问题,您还可以回滚到文档的先前版本。如果您使用这样的架构ObjectId.getTimestamp(),那么您只需要它,它不依赖于 Mongoose。


原始答案:

如果您使用 ObjectId 作为您的身份字段,则不需要该created_at字段。ObjectIds 有一个名为getTimestamp().

ObjectId("507c7f79bcf86cd7994f6c0e").getTimestamp()

这将返回以下输出:

ISODate("2012-10-15T21:26:17Z")

此处的更多信息如何从 Mongo ObjectID 中提取创建日期

为了添加updated_at文件,你需要使用这个:

var ArticleSchema = new Schema({
  updated_at: { type: Date }
  // rest of the fields go here
});

ArticleSchema.pre('save', function(next) {
  this.updated_at = Date.now();
  next();
});
于 2013-02-28T23:01:31.980 回答
244

从 Mongoose 4.0 开始,您现在可以在 Schema 上设置时间戳选项,让 Mongoose 为您处理:

var thingSchema = new Schema({..}, { timestamps: true });

您可以更改使用的字段的名称,如下所示:

var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } });

http://mongoosejs.com/docs/guide.html#timestamps

于 2015-10-20T17:25:27.657 回答
136

这就是我最终做的事情:

var ItemSchema = new Schema({
    name    : { type: String, required: true, trim: true }
  , created_at    : { type: Date }
  , updated_at    : { type: Date }
});


ItemSchema.pre('save', function(next){
  now = new Date();
  this.updated_at = now;
  if ( !this.created_at ) {
    this.created_at = now;
  }
  next();
});
于 2012-10-01T09:20:54.973 回答
115

使用 Schema 的内置timestamps选项。

var ItemSchema = new Schema({
    name: { type: String, required: true, trim: true }
},
{
    timestamps: true
});

这将自动将createdAtupdatedAt字段添加到您的架构中。

http://mongoosejs.com/docs/guide.html#timestamps

于 2016-03-07T18:04:25.077 回答
31

然后添加timestamps到您Schema喜欢的内容中createdAtupdatedAt并将自动为您生成

var UserSchema = new Schema({
    email: String,
    views: { type: Number, default: 0 },
    status: Boolean
}, { timestamps: {} });

在此处输入图像描述
你也可以createdAt -> created_at改变

timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
于 2016-11-05T15:33:27.530 回答
29

如果使用update()findOneAndUpdate()

{upsert: true}选项

您可以使用$setOnInsert

var update = {
  updatedAt: new Date(),
  $setOnInsert: {
    createdAt: new Date()
  }
};
于 2014-09-04T15:01:28.403 回答
9

这就是我创建和更新的方式。

在我的架构中,我添加了创建和更新的内容,如下所示:

   /**
     * 文章架构
     */
    var ArticleSchema = new Schema({
        创建:{
            类型:日期,
            默认值:Date.now
        },
        更新: {
            类型:日期,
            默认值:Date.now
        },
        标题: {
            类型:字符串,
            默认: '',
            修剪:真的,
            必填:'标题不能为空'
        },
        内容: {
            类型:字符串,
            默认: '',
            修剪:真
        },
        用户:{
            类型:Schema.ObjectId,
            参考:'用户'
        }
    });

然后在文章控制器内的文章更新方法中,我添加了:

/**
     * 更新一篇文章
     */
    出口。更新=功能(请求,水库){
        var 文章 = req.article;

        文章 = _.extend(文章, req.body);
        article.set("更新", Date.now());

        文章.保存(功能(错误){
            如果(错误){
                返回 res.status(400).send({
                    消息:errorHandler.getErrorMessage(err)
                });
            } 别的 {
                res.json(文章);
            }
        });
    };

粗体部分是感兴趣的部分。

于 2014-12-10T01:41:27.200 回答
9

对于带有猫鼬的 NestJs,使用这个

@Schema({timestamps: true})
于 2021-06-09T12:04:58.547 回答
7
var ItemSchema = new Schema({
    name : { type: String, required: true, trim: true }
});

ItemSchema.set('timestamps', true); // this will add createdAt and updatedAt timestamps

文档:https ://mongoosejs.com/docs/guide.html#timestamps

于 2019-03-04T07:40:00.137 回答
7

在您的模型架构中,只需添加一个属性timestamps并为其分配值true,如下所示:-

var ItemSchema = new Schema({
   name :  { type: String, required: true, trim: true },
},{timestamps : true}
);
于 2019-12-11T13:21:17.290 回答
7

在你的model

const User = Schema(
  {
    firstName: { type: String, required: true },
    lastName: { type: String, required: true },
    password: { type: String, required: true }
  },
  {
    timestamps: true
  }
);

之后你的modelincollection会是这样的:

{
    "_id" : ObjectId("5fca632621100c230ce1fb4b"),
    "firstName" : "first",
    "lastName" : "last",
    "password" : "$2a$15$Btns/B28lYIlSIcgEKl9eOjxOnRjJdTaU6U2vP8jrn3DOAyvT.6xm",
    "createdAt" : ISODate("2020-12-04T16:26:14.585Z"),
    "updatedAt" : ISODate("2020-12-04T16:26:14.585Z"),
}
于 2021-10-05T09:22:17.067 回答
4

您可以使用 的timestamp插件mongoose-troop将此行为添加到任何架构。

于 2012-10-01T13:47:56.323 回答
3

我们也可以通过使用模式插件来实现这一点。

helpers/schemaPlugin.js文件中

module.exports = function(schema) {

  var updateDate = function(next){
    var self = this;
    self.updated_at = new Date();
    if ( !self.created_at ) {
      self.created_at = now;
    }
    next()
  };
  // update date for bellow 4 methods
  schema.pre('save', updateDate)
    .pre('update', updateDate)
    .pre('findOneAndUpdate', updateDate)
    .pre('findByIdAndUpdate', updateDate);
};

并在models/ItemSchema.js文件中:

var mongoose = require('mongoose'),
  Schema   = mongoose.Schema,
  SchemaPlugin = require('../helpers/schemaPlugin');

var ItemSchema = new Schema({
  name    : { type: String, required: true, trim: true },
  created_at    : { type: Date },
  updated_at    : { type: Date }
});
ItemSchema.plugin(SchemaPlugin);
module.exports = mongoose.model('Item', ItemSchema);
于 2016-08-29T12:20:33.177 回答
3

你可以很容易地使用这个插件。从文档:

var timestamps = require('mongoose-timestamp');
var UserSchema = new Schema({
    username: String
});
UserSchema.plugin(timestamps);
mongoose.model('User', UserSchema);
var User = mongoose.model('User', UserSchema)

如果您愿意,还可以设置字段的名称:

mongoose.plugin(timestamps,  {
  createdAt: 'created_at', 
  updatedAt: 'updated_at'
});
于 2015-09-05T23:46:54.047 回答
2

我的猫鼬版本是 4.10.2

似乎只有钩子findOneAndUpdate在工作

ModelSchema.pre('findOneAndUpdate', function(next) {
  // console.log('pre findOneAndUpdate ....')
  this.update({},{ $set: { updatedAt: new Date() } });
  next()
})
于 2017-06-01T09:56:41.883 回答
2

如果您使用的是 nestjs 和 @Schema 装饰器,您可以像这样实现:

@Schema({
  timestamps: true,
})

timestamps 选项告诉 mongoose 将 createdAt 和 updatedAt 字段分配给您的架构。分配的类型是日期。

默认情况下,字段的名称是 createdAt 和 updatedAt。

通过设置 timestamps.createdAt 和 timestamps.updatedAt 自定义字段名称。

于 2021-07-29T06:43:50.463 回答
1
const mongoose = require('mongoose');
const config = require('config');
const util = require('util');

const Schema = mongoose.Schema;
const BaseSchema = function(obj, options) {
  if (typeof(options) == 'undefined') {
    options = {};
  }
  if (typeof(options['timestamps']) == 'undefined') {
    options['timestamps'] = true;
  }

  Schema.apply(this, [obj, options]);
};
util.inherits(BaseSchema, Schema);

var testSchema = new BaseSchema({
  jsonObject: { type: Object }
  , stringVar : { type: String }
});

现在您可以使用它,因此无需在每个表中都包含此选项

于 2016-09-16T08:33:24.263 回答
1

从 mongo 3.6 开始,您可以使用“更改流”: https ://emptysqua.re/blog/driver-features-for-mongodb-3-6/#change-streams

要使用它,您需要通过“监视”查询创建一个更改流对象,并且对于每个更改,您可以做任何您想做的事情......

蟒蛇解决方案:

def update_at_by(change):
    update_fields = change["updateDescription"]["updatedFields"].keys()
    print("update_fields: {}".format(update_fields))

    collection = change["ns"]["coll"]
    db = change["ns"]["db"]
    key = change["documentKey"]

    if len(update_fields) == 1 and "update_at" in update_fields:
        pass  # to avoid recursion updates...
    else:
        client[db][collection].update(key, {"$set": {"update_at": datetime.now()}})


client = MongoClient("172.17.0.2")
db = client["Data"]

change_stream = db.watch()

for change in change_stream:
    print(change)
    update_ts_by(change)

注意,要使用 change_stream 对象,您的 mongodb 实例应作为“副本集”运行。它也可以作为一个 1 节点副本集来完成(几乎没有变化然后独立使用):

运行 mongo 作为副本集: https ://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/

副本集配置与独立: Mongo DB - 独立和 1 节点副本集之间的区别

于 2020-09-03T09:38:13.520 回答
0

我实际上在后面这样做

如果更新一切顺利:

 // All ifs passed successfully. Moving on the Model.save
    Model.lastUpdated = Date.now(); // <------ Now!
    Model.save(function (err, result) {
      if (err) {
        return res.status(500).json({
          title: 'An error occured',
          error: err
        });
      }
      res.status(200).json({
        message: 'Model Updated',
        obj: result
      });
    });
于 2017-10-27T22:41:31.010 回答
0

使用函数返回计算的默认值:

var ItemSchema = new Schema({
    name: {
      type: String,
      required: true,
      trim: true
    },
    created_at: {
      type: Date,
      default: function(){
        return Date.now();
      }
    },
    updated_at: {
      type: Date,
      default: function(){
        return Date.now();
      }
    }
});

ItemSchema.pre('save', function(done) {
  this.updated_at = Date.now();
  done();
});
于 2015-12-29T20:26:02.717 回答
0

使用 machinepack-datetime 格式化日期时间。

tutorialSchema.virtual('createdOn').get(function () {
    const DateTime = require('machinepack-datetime');
    let timeAgoString = "";
    try {
        timeAgoString = DateTime.timeFrom({
            toWhen: DateTime.parse({
                datetime: this.createdAt
            }).execSync(),
            fromWhen: new Date().getTime()
        }).execSync();
    } catch(err) {
        console.log('error getting createdon', err);
    }
    return timeAgoString; // a second ago
});

与 express 或一般 Javascript 世界不同,Machine pack 具有清晰的 API,非常棒。

于 2017-12-08T17:16:33.500 回答
-2

您可以使用中间件virtuals。这是您所在updated_at领域的示例:

ItemSchema.virtual('name').set(function (name) {
  this.updated_at = Date.now;
  return name;
});
于 2012-10-01T09:15:52.963 回答