将created_at和updated_at字段添加到猫鼬模式


166

有没有一种方法可以将created_at和updated_at字段添加到猫鼬模式,而不必每次调用新的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 }
});

我完全按照您的做法进行了工作。使用猫鼬4.8.4。可能是新事物吗?
martinedwards,

1
这是很久以前的事了。
chovy

是的,我认为值得一提的是,以上内容现在可以使用了。
martinedwards '18 / 11/29

Answers:


131

从Mongoose 4.0开始,您现在可以在Schema上设置一个timestamps选项,让Mongoose为您处理:

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

您可以像这样更改使用的字段的名称:

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

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


2
同意,这是Mongoose 4.0中的最佳选择。
塔德·吉尔斯

258

更新:(5年后)

注意:如果您决定使用Kappa体系结构Event Sourcing + CQRS),则根本不需要更新日期。由于数据是不可变的,仅追加事件日志,因此您只需要事件创建日期。与Lambda体系结构类似,如下所述。然后,您的应用程序状态就是事件日志(衍生数据)的投影。如果您收到有关现有实体的后续事件,则将使用该事件的创建日期作为实体的更新日期。这是胶束服务系统中的一种常用(并且常常被误解)的做法。

更新:(4年后)

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

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

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

更新:(2.5年后)

现在,可以将#timestamps选项与猫鼬版本> = 4.0一起使用。

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

如果设置了时间戳,猫鼬为您的模式分配了createdAtupdatedAt域,则分配的类型为Date

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

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

注意:如果您正在处理具有关键数据的大型应用程序,则应重新考虑更新文档。我建议您使用不可变的仅追加数据(lambda体系结构)。这意味着您只允许插入。不允许更新和删除!如果您要“删除”记录,则可以轻松插入带有timestamp/ 字段的文档的新版本,version 然后将deleted字段设置为true。同样,如果您要更新文档,请创建一个新的文档,并更新相应的字段,然后复制其余字段。然后,要查询该文档,您将得到一个带有最新时间戳或最高版本的文档。而不是“删除”(deleted 字段未定义或为false”)。

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


原始答案:

如果您使用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();
});

3
您如何在Mongoose / node.js中做到这一点?
Zebra推进实验室

6
值得一提的是,即使不是被使用的解决方案,也很有趣!

但是,如果我想将创建日期传递给视图,则需要为此设置特殊变量,或者传递ID正确吗?

3
我很欣赏最初的答案,但提倡使用lambda架构听起来也像是解决5倍级别元数据问题的好方法,并且可能永远不会交付,而不是构建CRUD应用并使其保持简单,除非确实需要这种方法的复杂性。请记住,您所发布的有关MongoDB的信息“很少”开始扩展,并且您主张每次写入都创下新记录,这将以任何有意义的规模迅速杀死Mongo。将其移至卡桑德拉(Cassandra)部分...
约翰·库尔维纳

1
由于此答案中提供的信息,我实际上更改了后端设计,以便执行软删除来代替实际删除。它提供了一些更有用的更深入的知识。
肯纳

133

这就是我最终要做的事情:

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

8
1.将当前时间存储在本地var中并分配它,而不是每次调用new Date()时都要分配它,这将确保第一遍create_at和updated_at具有相同的exect值。2. new Date => new Date()
Shay Erlichmen 2013年

13
只是要指出,如果使用ObjectId,则可以从那里获取created_at...。您不需要单独的字段。getTimestamp()

6
created_at的其他选项可能是将模型更改为-> created_at:{类型:日期,默认值:Date.now},
OscarVGG 2014年

1
@ajbraus做一个模式插件
wlingke

2
还应Date.now()尽可能使用它而不是new Date更快,因为它是一种静态方法
karlkurzer 2016年

107

timestamps对您的模式使用内置选项。

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

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

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


1
需要猫鼬版本> = 4.0
Jensen

2
我发现文档不清楚-这会添加字段,但是还可以确保每次更新时都对它们进行更新吗?
路德维克

通常,createdAt在对象创建时始终只存储一次。updatedAt更新每个新的保存(当obj更改时)
codyc4321

1
我得到了这个“ 2016-12-07T11:46:46.0​​66Z” ..请解释一下时间戳格式,如何更改时区?是采用mongoDB服务器时区?
Mahesh K

@mcompeau,谢谢您的回答!我知道这是一个远景,但是您是否还记得是否可以将以此方式创建的字段用作索引?
manidos

29

如果使用update()findOneAndUpdate()

{upsert: true}选择

您可以使用 $setOnInsert

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

1
这适用于大多数mongo库。更改为可接受的答案
chovy

1
如果您使用Mogo的默认_id字段,则不需要createdAt字段。在下面查看我的答案以获取更多详细信息。
帕维尔·尼科洛夫

1
...检查我的原始答案
帕维尔·尼科洛夫

25

然后添加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' }

2
现在,猫鼬为您完成了所有这些工作,我同意这是最好的解决方案。
文斯·鲍德伦

是的,就@VinceBowdren达成协议
Mr.spShuvo

8

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

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

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

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

/ **
     *更新文章
     * /
    exports.update = function(req,res){
        var article = req.article;

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

        article.save(function(err){
            如果(错误){
                返回res.status(400).send({
                    消息:errorHandler.getErrorMessage(err)
                });
            }其他{
                res.json(文章);
            }
        });
    };

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




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

2

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

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

2

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

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

这会做什么?
chovy

时间戳属性将在每个文档中添加created_at和Updated_at字段。Created_at字段指示文档的创建时间,updated_at字段指示文档的创建时间(如果有的话)的更新时间。两个字段的值均为ISO时间格式。希望这能消除您对Chovy的怀疑。
Pavneet Kaur

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

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


1

我的猫鼬版本是4.10.2

似乎只有钩子findOneAndUpdate是可行的

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

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

不需要包装Date.now()函数就可以了:...default: Date.now()
karlkurzer

1
我将其包装在一个函数中,以便可以在测试中模拟“ .now()”。否则,它在初始化期间只能运行一次,并且值不容易更改。
orourkedd '16

1
注意那default: Date.now()是错误的。如果有的话default: Date.now。否则,您的所有文档都将具有相同的时间戳:应用程序启动的时间;)
Max Truxa

我喜欢你的default: Date.now策略。干净得多。
orourkedd

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

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。


-2

您可以使用中间件虚拟机。这是您的updated_at领域的示例:

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

什么时候实际设置?而且会持续吗?那么从现在开始的3天,它还有3天之前的日期?
chovy,2012年

在您更改给定属性的情况下(在这种情况下),将调用虚拟函数name。是的,它应该是持久的。
zemirco

这将适用于Item对象上的所有字段吗?我不确定此解决方案是否
可以满足
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.