I'm running a MongoDB with access via Mongoose to store user records. I also have underscore on the server. I have a RESTful API with a route that returns a collection (array of objects) from the database. I want to return the full collection to the client but remove the password element from each object so that doesn't get sent to the client. Before anyone says anything, I will use bcrypt to salt and hash the password in the final version :)
Today I have just one entry in the database, for the user 'administrator'. Here's the code in my route:
app.get('/users', function(req, res) {
User.find().sort({'userName': 'ascending'}).exec(function(err, data) {
_.each(data, function (element, index, list) {
console.log('userName=' + element.userName);
console.log('password=' + element.password);
delete element.password;
console.log('keys: ' + _.keys(element));
console.log('password=' + element.password);
console.log(_.omit(element, 'password'));
});
res.json(data);
});
});
What I get sent back to the browser is:
[{"_id":"54058e6eb53dd60730295f59","modifiedOn":"2014-09-01T15:19:10.012Z",
"userName":"administrator","password":"stackoverflow","role":"administrator",
"__v":0,"createdBy":"54058e6eb53dd60730295f59","createdOn":"2014-09-01T15:19:10.004Z",
"previousLogins":[],"accountIsLocked":false,"loginAttempts":0}]
Which us fine, as the res.json(data)
statement is just sending the raw data
back to the browser - that's not the issue. The issue is that the delete
(and also if I use .omit
) don't seem to work on my collection! As you can see there are lots of console.log
for debugging, here's what gets output:
userName=administrator
password=stackoverflow
keys: $__,isNew,errors,_maxListeners,_doc,_pres,_posts,save,_events
password=stackoverflow
{ _id: 54058e6eb53dd60730295f59,
modifiedOn: Mon Sep 01 2014 19:19:10 GMT+0400 (GST),
userName: 'administrator',
password: 'stackoverflow',
role: 'administrator',
__v: 0,
createdBy: 54058e6eb53dd60730295f59,
createdOn: Mon Sep 01 2014 19:19:10 GMT+0400 (GST),
previousLogins: [],
accountIsLocked: false,
loginAttempts: 0 }
The output of _.keys
shows keys (I assume from an object prototype?) that I don't see when I console.log(element)
but none of the keys that are accessible via element.key
.
Any idea why I'm seeing this behaviour?
The problem is that data
passed into exec
callback function is actually a Document
object - which can be thought of as a collection of Models
created by Mongoose. These objects have plenty of useful methods, they remember connection with db etc. - but you won't be able to process them as plain objects.
The solution is to instruct Mongoose that you actually want plain JS objects as result of the query with lean()
:
User.find().sort({'userName': 'ascending'}).lean().exec(function(err, data) {
// process the data
});
Alternatively, you should be able to turn each model into a plain object with .toObject()
method, then filter it:
var filtered = _.map(data, function(model) {
return _.omit(model.toObject(), 'password');
});
res.json(filtered);
... but I'd rather use the first approach. )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With