I'm attempting to iterate over fields in a mongoose model within a middleware function. The current context this
is the model object itself. So I have a function in which the context is a Javascript object like this:
{
lastName: 'Wilkens',
firstName: 'Elepart',
name: 'Elepart Wilkens',
username: 'eK',
bio: '<script>alert(\'this is a hack!!\')',
_id: 53b17dd0e8c5af50c1d73bc6,
language: 'en',
country: 'USA',
online: true
}
I want to iterate over this object (which is represented in the current function with this
). Every time I attempt to iterate with loops, it prints out values that look like internal Javascript metadata. Is it possible to iterate over this
within a function if this
represents an object?
Here's the actual middleware function:
userSchema.pre('save', function (next) {
console.log(this); // This prints precisely the same object I have copied above
var fields = Object.keys(this);
for(var i = 0; i < fields.length; i++) {
console.log(this[fields[i]]);
}
for(var key in this) {
if(this.hasOwnProperty(key)) {
console.log(this[key]);
}
}
});
And the output is:
{
strictMode: true,
selected: undefined,
shardval: undefined,
saveError: undefined,
validationError: undefined,
adhocPaths: undefined,
removing: undefined,
inserting: undefined,
version: undefined,
getters: {},
_id: undefined,
populate: undefined,
populated: undefined,
wasPopulated: false,
scope: undefined,
activePaths:
{ paths:
{ username: 'modify',
firstName: 'modify',
name: 'modify',
online: 'default',
country: 'default',
language: 'default',
_id: 'default',
bio: 'modify',
lastName: 'modify' },
states: { default: [Object], init: {}, modify: [Object], require: {} },
stateNames: [ 'require', 'modify', 'init', 'default' ],
map: [Function] },
ownerDocument: undefined,
fullPath: undefined }
true
undefined
0
{ online: true,
country: 'USA',
language: 'en',
_id: 53b1825a00ed9af7c12eedf9,
bio: '<script>alert(\'this is a hack!!\')',
username: 'yK',
name: 'Yershay Wilkens',
firstName: 'Yershay',
lastName: 'Wilkens' }
{ save:
[ { [Function] isAsync: false },
{ [Function: checkForExistingErrors] isAsync: false },
{ [Function: validation] isAsync: false },
{ [Function] isAsync: false },
{ [Function] isAsync: false } ],
validate: [ { [Function] isAsync: false } ] }
{ save: [], validate: [] }
{ [Function] numAsyncPres: 0 }
{ [Function] numAsyncPres: 0 }
{}
I'm attempting to iterate over fields in a mongoose model within a middleware function. The current context this
is the model object itself. So I have a function in which the context is a Javascript object like this:
{
lastName: 'Wilkens',
firstName: 'Elepart',
name: 'Elepart Wilkens',
username: 'eK',
bio: '<script>alert(\'this is a hack!!\')',
_id: 53b17dd0e8c5af50c1d73bc6,
language: 'en',
country: 'USA',
online: true
}
I want to iterate over this object (which is represented in the current function with this
). Every time I attempt to iterate with loops, it prints out values that look like internal Javascript metadata. Is it possible to iterate over this
within a function if this
represents an object?
Here's the actual middleware function:
userSchema.pre('save', function (next) {
console.log(this); // This prints precisely the same object I have copied above
var fields = Object.keys(this);
for(var i = 0; i < fields.length; i++) {
console.log(this[fields[i]]);
}
for(var key in this) {
if(this.hasOwnProperty(key)) {
console.log(this[key]);
}
}
});
And the output is:
{
strictMode: true,
selected: undefined,
shardval: undefined,
saveError: undefined,
validationError: undefined,
adhocPaths: undefined,
removing: undefined,
inserting: undefined,
version: undefined,
getters: {},
_id: undefined,
populate: undefined,
populated: undefined,
wasPopulated: false,
scope: undefined,
activePaths:
{ paths:
{ username: 'modify',
firstName: 'modify',
name: 'modify',
online: 'default',
country: 'default',
language: 'default',
_id: 'default',
bio: 'modify',
lastName: 'modify' },
states: { default: [Object], init: {}, modify: [Object], require: {} },
stateNames: [ 'require', 'modify', 'init', 'default' ],
map: [Function] },
ownerDocument: undefined,
fullPath: undefined }
true
undefined
0
{ online: true,
country: 'USA',
language: 'en',
_id: 53b1825a00ed9af7c12eedf9,
bio: '<script>alert(\'this is a hack!!\')',
username: 'yK',
name: 'Yershay Wilkens',
firstName: 'Yershay',
lastName: 'Wilkens' }
{ save:
[ { [Function] isAsync: false },
{ [Function: checkForExistingErrors] isAsync: false },
{ [Function: validation] isAsync: false },
{ [Function] isAsync: false },
{ [Function] isAsync: false } ],
validate: [ { [Function] isAsync: false } ] }
{ save: [], validate: [] }
{ [Function] numAsyncPres: 0 }
{ [Function] numAsyncPres: 0 }
{}
Share
Improve this question
edited Jul 3, 2014 at 15:03
Glen Selle
asked Jun 30, 2014 at 15:16
Glen SelleGlen Selle
3,9564 gold badges38 silver badges59 bronze badges
6
- 1 Can you post the loop you are currently using? – Duane Commented Jun 30, 2014 at 15:18
- 1 or could you set up a fiddle ? i think it is possible – john Smith Commented Jun 30, 2014 at 15:18
- 1 Without more code we can't help you. Though here is an example of how it could work: jsbin./gomisuyu/1 – Yoshi Commented Jun 30, 2014 at 15:23
- I've added more code. A JSfiddle wouldn't be as helpful since this is all with Mongoose, so it be a bit hard to replicate in the browser. – Glen Selle Commented Jun 30, 2014 at 15:25
-
When iterating over an object (not an array) try using "for in"
for ( key in object )
as well ashasOwnProperty
as answered here stackoverflow./questions/684672/… – tastybytes Commented Jun 30, 2014 at 15:27
3 Answers
Reset to default 6You're using integer indexes instead of the string references from the fields array. It should be:
var fields = Object.keys(this);
for(var i = 0; i < fields.length; i++) {
console.log(this[fields[i]]);
}
(e.g., you were doing this[1]
, this[2]
, instead of this[fields[1]]
)
@JohnnyHK's ment worked for me:
const user = new User();
const schemaKeys = Object.keys(user.toObject());
I found a slightly different way to acplish what I wanted which was to iterate over the model properties of a Mongoose model within a middleware function. This uses async.js, but you could refactor it to use a generic JS loop or any other control flow library. The key is to get an array of the document's fields, then you can iterate over those and get/set the values using the current context with this
. As far as I know, this will not coerce non-string values into strings. I've tested it with strings, numbers, booleans and objectIds and they are successfully saved as their original data types.
yourSchema.pre('save', function (next) {
var self = this;
// Get the document's fields
var fields = Object.keys(this._doc);
// Do whatever you want for each field
async.each(fields, function(field, cb) {
self[field] = validator.escape(self[field]);
cb();
}, function(err){
next();
});
});