将created_at和updated_at字段添加到mongoose模式

时间:2012-10-01 08:13:47

标签: node.js mongodb express mongoose

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

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

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

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

21 个答案:

答案 0 :(得分:224)

更新:(5年后)

  

注意:如果您决定使用Kappa Architecture事件采购+ CQRS ),则根本不需要更新日期。由于您的数据是一个不可变的仅附加事件日志,因此您只需要事件创建日期。与 Lambda Architecture 类似,如下所述。然后,您的应用程序状态是事件日志(派生数据)的投影。如果您收到有关现有实体的后续事件,则您将使用该事件的创建日期作为您实体的更新日期。这是微服务系统中常用的(通常被误解的)实践。

更新:(4年后)

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

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

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

更新:(2。5年后)

现在,您可以使用#timestamps选项与mongoose版本> = 4.0。

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

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

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

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

注意:如果您正在处理包含关键数据的大型应用程序,则应重新考虑更新文档。我建议你使用不可变的,仅附加数据(lambda architecture)。这意味着什么   你只允许插入。 不应该更新和删除   允许!如果你想“删除”一条记录,你可以很容易   使用一些timestamp / version插入新版本的文档   提交,然后将deleted字段设置为true。同样如果你想   更新文档 - 您使用适当的文档创建一个新文档   字段已更新,其余字段已复制。然后为了   查询此文档,您将获得具有最新时间戳的那个或   未被“删除”的最高版本(deleted字段未定义或为false)。

     

数据不变性可确保您的数据可调试 - 您可以跟踪   每个文件的历史。您也可以回滚到之前的版本   如果出现问题,文档的版本。如果你去这样的话   架构ObjectId.getTimestamp()就是你所需要的,而事实并非如此   依赖猫鼬。


原始答案:

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

ObjectId("507c7f79bcf86cd7994f6c0e").getTimestamp()

这将返回以下输出:

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

此处有更多信息How do I extract the created date out of a 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();
});

答案 1 :(得分:129)

这就是我最终做的事情:

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();
});

答案 2 :(得分:102)

对Schema使用内置timestamps选项。

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

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

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

答案 3 :(得分:69)

从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

答案 4 :(得分:28)

如果使用update()findOneAndUpdate()

使用{upsert: true}选项

您可以使用$setOnInsert

var update = {
  updatedAt: new Date(),
  $setOnInsert: {
    createdAt: new Date()
  }
};

答案 5 :(得分:23)

timestamps添加到您的Schema,然后createdAtupdatedAt会自动为您生成

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

enter image description here
您也可以通过

更改createdAt -> created_at
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }

答案 6 :(得分:8)

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

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

   /**
     * Article Schema
     */
    var ArticleSchema = new Schema({
        created: {
            type: Date,
            default: Date.now
        },
        updated: {
            type: Date,
            default: Date.now
        },
        title: {
            type: String,
            default: '',
            trim: true,
            required: 'Title cannot be blank'
        },
        content: {
            type: String,
            default: '',
            trim: true
        },
        user: {
            type: Schema.ObjectId,
            ref: 'User'
        }
    });

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

/**
     * Update a article
     */
    exports.update = function(req, res) {
        var article = req.article;

        article = _.extend(article, req.body);
        article.set("updated", Date.now());

        article.save(function(err) {
            if (err) {
                return res.status(400).send({
                    message: errorHandler.getErrorMessage(err)
                });
            } else {
                res.json(article);
            }
        });
    };

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

答案 7 :(得分:4)

您可以使用mongoose-troop的{​​{3}}插件将此行为添加到任何架构中。

答案 8 :(得分:3)

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

答案 9 :(得分:2)

您可以非常轻松地使用this plugin。 来自文档:

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'
});

答案 10 :(得分:1)

我们也可以通过架构插件来实现这一点。

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);

答案 11 :(得分:1)

对于带有 Mongoose 的 NestJs,使用这个

@Schema({timestamps: true})

答案 12 :(得分:1)

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

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

python解决方案:

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 - difference between standalone & 1-node replica set

答案 13 :(得分:1)

在模型架构中,只需添加属性时间戳并为其分配值 true 即可,如下所示:-

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

答案 14 :(得分:1)

我的猫鼬版本是4.10.2

似乎只有钩子findOneAndUpdate正在工作

ModelSchema.pre('findOneAndUpdate', function(next) {
  // console.log('pre findOneAndUpdate ....')
  this.update({},{ $set: { updatedAt: new Date() } });
  next()
})

答案 15 :(得分: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
      });
    });

答案 16 :(得分: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
});

与快速或一般的Javascript世界不同,机器包具有清晰的API。

答案 17 :(得分:0)

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 }
});

现在您可以使用它,这样就不需要在每个表中包含此选项

答案 18 :(得分:0)

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

@Schema({
  timestamps: true,
})

时间戳选项告诉猫鼬将 createdAt 和 updatedAt 字段分配给您的架构。分配的类型是日期。

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

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

答案 19 :(得分:-1)

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

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();
});

答案 20 :(得分:-3)

您可以使用middlewarevirtuals。以下是updated_at字段的示例:

ItemSchema.virtual('name').set(function (name) {
  this.updated_at = Date.now;
  return name;
});