Razvan M.
Razvan M.

Reputation: 407

Node.Js Express and Mongoose Response Model Modify

I'm quite new to Node.js development. Also callbacks still quite bedazzle me although I have some experience with async functions.

I'm using mongoose's .find() function to search in a Users collection in the DB. The problem is I also want to display these users but I wouldn't want to display all the properties availible in the Database.

...
function(req,res){
    User.find(function(err,users){
        res.json(users);
    }) 
}
...

This is how I'm currently getting all my users in the DB, but this also return passwords and other sensitive information. I would like to know the most effiecient way to "convert" this data into the same object without some properties or with altered properties like adding a "fullName" comprised of firstName + lastName;

So when returning all the users I would like to have something like

...
function(req,res){
    User.find(function(err,users){
        res.json(users.convertToOtherModel());
    }) 
}
...

Not sure the "convertToOtherModel" function can be placed somewhere so that it works on users... but any idea on how to do this would help!

Upvotes: 1

Views: 1760

Answers (4)

Yasser Hussain
Yasser Hussain

Reputation: 854

Override toJSON method of your User schema.

UserSchema.methods.toJSON = function () {
  var user = this;
  // Modify your document object here
  return { fullName: user.firstName + " " + user.lastName }
  // Pick other fields too if you want
  // _.pick(user, ["otherField"]);
};

Then send them like so -

User.find(function(err,users){
  res.json(users);
}) 

Upvotes: 1

blogbydev
blogbydev

Reputation: 1495

personSchema
    .virtual('fullName')
    .get(function () {
        return this.name.first + ' ' + this.name.last;
    })
    .set(function (v) {
        this.name.first = v.substr(0, v.indexOf(' '));
        this.name.last = v.substr(v.indexOf(' ') + 1);
    })
  1. For something like FullName you can create virtual schemas.

    Link here: http://mongoosejs.com/docs/guide.html

  2. You will have to choose what columns you want to output, i am not sure if you can specifically blacklist a column(All columns minus password column)

Upvotes: 2

Nenad Vracar
Nenad Vracar

Reputation: 122077

Instead of making query to return all fields you can pass second argument to find() and specify which fields you want or don't want to return

User.find({}, {password: 0}, function(error, users) {
  console.log(users)
})

You can also use aggregation framework and create new field by concating values of different fields

User.aggregate([
    {$project: {
        username: '$username',
        fullName: {$concat: ['$firstName', ' ', '$lastName']}
    }}
    ], function(error, users) {
        console.log(users)
    })

Upvotes: 1

rsp
rsp

Reputation: 111414

You can do something like this to return only some of the properties:

function filterUser(user) {
  let { property1, property2 } = user;
  return { property1, property2 };
}
res.json( users.map(filterUser) );

Or a more portable way using lodash:

res.json( users.map(user => _.pick(user, ['prop1', 'prop2']));

See: https://lodash.com/docs/4.17.4#pick

To use the lodash version you first need to add:

const _ = require('lodash');

to your code, and run this in your project's directory:

npm install lodash --save

Upvotes: 2

Related Questions