add created_at and updated_at fields to mongoose schemas

Is there a way to add created_at and updated_at fields to a mongoose schema, without having to pass them in everytime new MyModel() is called?

The created_at field would be a date and only added when a document is created. The updated_at field would be updated with new date whenever save() is called on a document.

I have tried this in my schema, but the field does not show up unless I expcitly add it:

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

This is what I ended up doing:

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

If you are using ObjectId as your identity field you don't need created_at field. ObjectIds have a method called getTimestamp().

ObjectId("507c7f79bcf86cd7994f6c0e").getTimestamp()

This will return the following output:

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

More info here How do I extract the created date out of a Mongo ObjectID

In order to add updated_at filed you need to use this:

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

ArticleSchema.pre('save', function(done) {
  this.updated_at = new Date();
  done();
});

This is how I achieved having created and updated.

Inside my schema I added the created and updated like so:

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

Then in my article update method inside the article controller I added:

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

The bold sections are the parts of interest.

You can use the timestamp plugin of mongoose-troop to add this behavior to any schema.

If use update() or findOneAndUpdate()

with {upsert: true} option

you can use $setOnInsert

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

You can use middleware and virtuals. Here is an example for your updated_at field:

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