How to save userId in mongoose hook?

4.6k Views Asked by At

Given yon schema, how do I save userId to createdBy and updatedBy?

This seems like it should be an easy use case. How do I do it?

I'm not sure how to get userId from req.user.id to the model before being written.

// graph.model.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var schema = new Schema({
  title: String,

  createdAt: Date,
  createdBy: String,
  updatedAt: Date,
  updatedBy: String,
});

// This could be anything
schema.pre('save', function (next) {
-  if (!this.createdAt) {
    this.createdAt = this.updatedAt = new Date;
    this.createdBy = this.updatedBy = userId;
  } else if (this.isModified()) {
    this.updatedAt = new Date;
    this.updatedBy = userId;
  }
  next();
});

Here's the controller code if you're interested:

var Graph = require('./graph.model');

// Creates a new Graph in the DB.
exports.create = function(req, res) {
  Graph.create(req.body, function(err, thing) {
    if(err) { return handleError(res, err); }
    return res.status(201).json(thing);
  });
};

// Updates an existing thing in the DB.
exports.update = function(req, res) {
  if(req.body._id) { delete req.body._id; }
  Graph.findById(req.params.id, function (err, thing) {
    if (err) { return handleError(res, err); }
    if(!thing) { return res.send(404); }
    var updated = _.merge(thing, req.body);
    updated.save(function (err) {
      if (err) { return handleError(res, err); }
      return res.json(thing);
    });
  });
};
2

There are 2 best solutions below

0
On BEST ANSWER

You can't access req object inside of mongoose hook.

I think, you should define virtual field with a smart setter instead:

schema.virtual('modifiedBy').set(function (userId) {
  if (this.isNew()) {
    this.createdAt = this.updatedAt = new Date;
    this.createdBy = this.updatedBy = userId;
  } else {
    this.updatedAt = new Date;
    this.updatedBy = userId;
  }
});

Now all you have to do is to set modifiedBy field with correct userId value in your controller:

var updated = _.merge(thing, req.body, {
  modifiedBy: req.user.id
});
0
On

The following is just another way of saving userId.

Sample model with createdBy, updatedBy, createdAt, updatedAt fields:

import mongoose from 'mongoose';

const SupplierSchema = new mongoose.Schema(
  {
    name: {
      type: String,
    },
    createdBy: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
    },
    updatedBy: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
    },
  },
 {
   timestamps: {
     createdAt: true,
     updatedAt: true,
   },
 },
);

export default mongoose.model('Supplier', SupplierSchema);

Note that in mongoose starting from version ^4.13.17 you can simply specify timestamps createdAt, updatedAt directly in the schema. https://mongoosejs.com/docs/4.x/docs/guide.html#timestamps

Then in supplier controller assign req.user._id to the fields createdBy, updatedBy:

import mongoose from 'mongoose';
import { Supplier } from '../models';

exports.create = async (req, res) => {
  const supplierToCreate = new Supplier({
    _id: new mongoose.Types.ObjectId(),
    name: req.body.name,
    createdBy: req.user._id,
    updatedBy: req.user._id,
  });

  return supplierToCreate
    .save()
    .then(() =>
      res.status(201).json({
        message: 'New supplier is created successfully.',
      }),
    )
    .catch(errSaving => res.status(500).json({ error: errSaving }));
};