Allow hiding schema fields when calling toJSON #1020

Closed
reaktivo opened this Issue Jul 20, 2012 · 49 comments

Comments

Projects
None yet
@reaktivo

This is a feature request to allow hiding of a schema field when converting the document into json. I'm not sure if it would be better if this was set from inside the schema declaration or from the toJSON call, e.g.

user = new Schema
  username: 
    type: String
  password:
    type: String
    expose: false

or something like

User.findOne({username: 'joe'}, function(err, doc) {
  user = doc.toJSON(hide: 'password')
});
@jamiter

This comment has been minimized.

Show comment Hide comment
@jamiter

jamiter Aug 2, 2012

Or maybe:

User.findOne({username: 'joe'}).deselect(['password']).exec(function(err, doc) {
  user = doc.toJSON();
});

Of course you can also simply only select the username:

User.findOne({username: 'joe'}).select(['username']).exec(function(err, doc) {
  user = doc.toJSON();
});

But this would mean that newly added fields wouldn't be retrieved.

jamiter commented Aug 2, 2012

Or maybe:

User.findOne({username: 'joe'}).deselect(['password']).exec(function(err, doc) {
  user = doc.toJSON();
});

Of course you can also simply only select the username:

User.findOne({username: 'joe'}).select(['username']).exec(function(err, doc) {
  user = doc.toJSON();
});

But this would mean that newly added fields wouldn't be retrieved.

@reaktivo

This comment has been minimized.

Show comment Hide comment
@reaktivo

reaktivo Aug 2, 2012

Cool, I like the .deselect solution, I didn't know it existed. Thanks.

– M

On Aug 2, 2012, at 6:29 AM, Michiel ter Reehorst wrote:

Or maybe:

User.findOne({username: 'joe'}).deselect(['password']).exec(function(err, doc) {
user = doc.toJSON();
});

Of course you can also simply only select the username:

User.findOne({username: 'joe'}).select(['username']).exec(function(err, doc) {
user = doc.toJSON();
});

But this would mean that newly added fields wouldn't be retrieved.


Reply to this email directly or view it on GitHub:
LearnBoost#1020 (comment)

reaktivo commented Aug 2, 2012

Cool, I like the .deselect solution, I didn't know it existed. Thanks.

– M

On Aug 2, 2012, at 6:29 AM, Michiel ter Reehorst wrote:

Or maybe:

User.findOne({username: 'joe'}).deselect(['password']).exec(function(err, doc) {
user = doc.toJSON();
});

Of course you can also simply only select the username:

User.findOne({username: 'joe'}).select(['username']).exec(function(err, doc) {
user = doc.toJSON();
});

But this would mean that newly added fields wouldn't be retrieved.


Reply to this email directly or view it on GitHub:
LearnBoost#1020 (comment)

@mrzafod

This comment has been minimized.

Show comment Hide comment
@mrzafod

mrzafod Aug 5, 2012

Other sample:

db = Schema({ ......
salt: {type: String, select: false}
});

db.method('showSalt', function() {
console.log(this.salt);
});

mongoose.model('db', db).findOne(..., function(err, doc) {
if(!err) doc.showSalt();
});

So, epic fail on 'showSalt'. I can not use 'select' or 'deselect', cause I need the doc as its defined in Schema. I gues it would be better with 'select: false' -> 'private: true' (to have access in schema's methods)

mrzafod commented Aug 5, 2012

Other sample:

db = Schema({ ......
salt: {type: String, select: false}
});

db.method('showSalt', function() {
console.log(this.salt);
});

mongoose.model('db', db).findOne(..., function(err, doc) {
if(!err) doc.showSalt();
});

So, epic fail on 'showSalt'. I can not use 'select' or 'deselect', cause I need the doc as its defined in Schema. I gues it would be better with 'select: false' -> 'private: true' (to have access in schema's methods)

@jamiter

This comment has been minimized.

Show comment Hide comment
@jamiter

jamiter Aug 7, 2012

@reaktivo Sorry if I didn't make myself clear but I meant that .deselect() would be nice to have. It isn't really in the Mongoose api. I gave it as a possible alternative for hide.

jamiter commented Aug 7, 2012

@reaktivo Sorry if I didn't make myself clear but I meant that .deselect() would be nice to have. It isn't really in the Mongoose api. I gave it as a possible alternative for hide.

@mrzafod

This comment has been minimized.

Show comment Hide comment
@mrzafod

mrzafod Aug 17, 2012

Is it possible to do this?

var docModel = mongoose.model('someModel');
var newDoc = new docModel();
res.json(newDoc.toJSON(<list of properties here!>));

mrzafod commented Aug 17, 2012

Is it possible to do this?

var docModel = mongoose.model('someModel');
var newDoc = new docModel();
res.json(newDoc.toJSON(<list of properties here!>));
@jamiter

This comment has been minimized.

Show comment Hide comment
@jamiter

jamiter Aug 17, 2012

@reaktivo I had another look at the documentation and this might be intresting to you:

// include a and b, exclude c
query.select('a b -c');

This is of course not the same thing as changing the toJSON function but it at leasts give the ability to retrieve the user without the password

jamiter commented Aug 17, 2012

@reaktivo I had another look at the documentation and this might be intresting to you:

// include a and b, exclude c
query.select('a b -c');

This is of course not the same thing as changing the toJSON function but it at leasts give the ability to retrieve the user without the password

@reaktivo

This comment has been minimized.

Show comment Hide comment
@reaktivo

reaktivo Aug 17, 2012

@jamiter that is kinda neat. Thanks.

@jamiter that is kinda neat. Thanks.

@mrzafod

This comment has been minimized.

Show comment Hide comment
@mrzafod

mrzafod Aug 18, 2012

I do not select anything in my sample! I have a Schema with a lots of fields. Most of them are with defaults and some fields are only for internal usage. So when I create new document I wouldn't get and use a whole Object! It's mostly because on 5000 - 10000 operations newDoc.toJSON() seems expensive and also not really safe

mrzafod commented Aug 18, 2012

I do not select anything in my sample! I have a Schema with a lots of fields. Most of them are with defaults and some fields are only for internal usage. So when I create new document I wouldn't get and use a whole Object! It's mostly because on 5000 - 10000 operations newDoc.toJSON() seems expensive and also not really safe

@jamiter

This comment has been minimized.

Show comment Hide comment
@jamiter

jamiter Aug 20, 2012

@mrzafod Reading from the documentation you can give an option parameter to toJSON:

http://mongoosejs.com/docs/api.html#document_Document-toJSON

But this does not give you the option to say which properties should be included or not.

It might be best to create your own function and add it to your models. Something like toFilteredJSON(filters)

schema.methods.toFilteredJSON = function (filters) {
  var json = {};
  # for each filter: add value to json
  return json;
})

jamiter commented Aug 20, 2012

@mrzafod Reading from the documentation you can give an option parameter to toJSON:

http://mongoosejs.com/docs/api.html#document_Document-toJSON

But this does not give you the option to say which properties should be included or not.

It might be best to create your own function and add it to your models. Something like toFilteredJSON(filters)

schema.methods.toFilteredJSON = function (filters) {
  var json = {};
  # for each filter: add value to json
  return json;
})
@mrzafod

This comment has been minimized.

Show comment Hide comment
@mrzafod

mrzafod Aug 20, 2012

@jamiter I gues its the only way

mrzafod commented Aug 20, 2012

@jamiter I gues its the only way

@jamiter

This comment has been minimized.

Show comment Hide comment
@jamiter

jamiter Aug 20, 2012

You could also add a filter functionality to the toJSON function and ask for a pull request :)

jamiter commented Aug 20, 2012

You could also add a filter functionality to the toJSON function and ask for a pull request :)

@olalonde

This comment has been minimized.

Show comment Hide comment
@olalonde

olalonde Oct 16, 2012

Contributor

Has anyone solved this yet? Otherwise I'll write that functionality when I have time. How about:

schema.set('toJSON', { hide: 'password salt' })

or maybe

var User = new Schema({
   password:                { type: String, toJSON: false }
   , salt:                  { type: String, toJSON: false }
});

There should probably be an option to ignore this, like:

doc.toJSON({showAll: true}); or doc.toJSON({ignoreOptions: true}); or doc.toRawJSON();

Contributor

olalonde commented Oct 16, 2012

Has anyone solved this yet? Otherwise I'll write that functionality when I have time. How about:

schema.set('toJSON', { hide: 'password salt' })

or maybe

var User = new Schema({
   password:                { type: String, toJSON: false }
   , salt:                  { type: String, toJSON: false }
});

There should probably be an option to ignore this, like:

doc.toJSON({showAll: true}); or doc.toJSON({ignoreOptions: true}); or doc.toRawJSON();

@chovy

This comment has been minimized.

Show comment Hide comment
@chovy

chovy Oct 16, 2012

salt: {type: String, select: false}

this seems like the easiest, and safest so you don't accidently print it out somewhere.

edit: woops, that will break login which needs salt.

I agree with olalonde's suggestion above.

chovy commented Oct 16, 2012

salt: {type: String, select: false}

this seems like the easiest, and safest so you don't accidently print it out somewhere.

edit: woops, that will break login which needs salt.

I agree with olalonde's suggestion above.

@lbeschastny

This comment has been minimized.

Show comment Hide comment
@lbeschastny

lbeschastny Oct 16, 2012

Contributor

@olalonde, by adding toJSON: false to your schema you can't hide system fields like _id.
So, there should be an alternative way.
For example, it may be some static schema function:

User.toJSON({password:false, salt: false})
Contributor

lbeschastny commented Oct 16, 2012

@olalonde, by adding toJSON: false to your schema you can't hide system fields like _id.
So, there should be an alternative way.
For example, it may be some static schema function:

User.toJSON({password:false, salt: false})
@topaxi

This comment has been minimized.

Show comment Hide comment
@topaxi

topaxi Oct 16, 2012

I wanted to do the same in an application of mine, I ended up using JSON.stringify(model, ['all', 'the', 'fields', 'you', 'want']);. The opposite to hide would be nice, but doesn't belong to mongoose in my opinion. It should be easy to implement a generic stringify for your app which allows "hiding". :)

topaxi commented Oct 16, 2012

I wanted to do the same in an application of mine, I ended up using JSON.stringify(model, ['all', 'the', 'fields', 'you', 'want']);. The opposite to hide would be nice, but doesn't belong to mongoose in my opinion. It should be easy to implement a generic stringify for your app which allows "hiding". :)

@lbeschastny

This comment has been minimized.

Show comment Hide comment
@lbeschastny

lbeschastny Oct 16, 2012

Contributor

@topaxi, your solution is good when you aren't using populates.
But what if you want to hide some fields in the populated object?
And what if this populated object located somewhere deep within the original object?

Defining toJSON selection options on the schema level can easily solve this problem.

Contributor

lbeschastny commented Oct 16, 2012

@topaxi, your solution is good when you aren't using populates.
But what if you want to hide some fields in the populated object?
And what if this populated object located somewhere deep within the original object?

Defining toJSON selection options on the schema level can easily solve this problem.

@jamiter

This comment has been minimized.

Show comment Hide comment
@jamiter

jamiter Oct 16, 2012

+1 for a simple hide option:

Person.toJSON({hide: 'private parts'})

I rather do this in my controller or router then define it in the model because most of the time it's request or view specific (which means overruling what you defined as default).

Whatever it will be, I'll be happy to see this functionality.

jamiter commented Oct 16, 2012

+1 for a simple hide option:

Person.toJSON({hide: 'private parts'})

I rather do this in my controller or router then define it in the model because most of the time it's request or view specific (which means overruling what you defined as default).

Whatever it will be, I'll be happy to see this functionality.

@topaxi

This comment has been minimized.

Show comment Hide comment
@topaxi

topaxi Oct 16, 2012

@lbeschastny how would the call look then? You aren't going to call the toJSON method on each populated object where/how you could specifiy the hidden properties on the models toJSON method (like to proposals above)?

If they're defined on schema level, like you said, it would be fine. Something like a private field.

new Schema({foo: { type: String, private: true })

(this is just an example, name for this is debatable) which would not show up in Schema#toJSON(). The proposed changes to Schema#toJSON() don't make sense imho.

topaxi commented Oct 16, 2012

@lbeschastny how would the call look then? You aren't going to call the toJSON method on each populated object where/how you could specifiy the hidden properties on the models toJSON method (like to proposals above)?

If they're defined on schema level, like you said, it would be fine. Something like a private field.

new Schema({foo: { type: String, private: true })

(this is just an example, name for this is debatable) which would not show up in Schema#toJSON(). The proposed changes to Schema#toJSON() don't make sense imho.

@olalonde

This comment has been minimized.

Show comment Hide comment
@olalonde

olalonde Oct 16, 2012

Contributor

I think this should definitely be in the schema definition somewhere...

How about

userSchema.set('toJSON', { hide: 'password salt' });

(this syntax is already used to show/hide virtuals and getters when calling toJSON, see http://mongoosejs.com/docs/api.html#document_Document-toJSON)

When calling

user.toJSON(); 

the paths 'password' and 'salt' would be hidden. We could also add a helper method that doesn't care about hidden paths.

user.toJSON({hide:false})

which should behave just like the old toJSON.

Contributor

olalonde commented Oct 16, 2012

I think this should definitely be in the schema definition somewhere...

How about

userSchema.set('toJSON', { hide: 'password salt' });

(this syntax is already used to show/hide virtuals and getters when calling toJSON, see http://mongoosejs.com/docs/api.html#document_Document-toJSON)

When calling

user.toJSON(); 

the paths 'password' and 'salt' would be hidden. We could also add a helper method that doesn't care about hidden paths.

user.toJSON({hide:false})

which should behave just like the old toJSON.

@chovy

This comment has been minimized.

Show comment Hide comment
@chovy

chovy Oct 16, 2012

I don't ever call toJSON(), how would this work if I just did:

res.json(userObject);

You can't set it on the schema because you will need the property in some situations, otherwise there is no need to have the property at all.

chovy commented Oct 16, 2012

I don't ever call toJSON(), how would this work if I just did:

res.json(userObject);

You can't set it on the schema because you will need the property in some situations, otherwise there is no need to have the property at all.

@olalonde

This comment has been minimized.

Show comment Hide comment
@olalonde

olalonde Oct 16, 2012

Contributor

Let me know what you guys think. I went for this option:

userSchema.set('toJSON', { hide: 'password salt someNestedField.secret' });

It also supports hiding fields in arrays (where friends is an array of users):

userSchema.set('toJSON', { hide: 'friends.password friends.salt' });

This will only affect the user.toJSON() call, the properties will still be accessible from your document like usual.

Contributor

olalonde commented Oct 16, 2012

Let me know what you guys think. I went for this option:

userSchema.set('toJSON', { hide: 'password salt someNestedField.secret' });

It also supports hiding fields in arrays (where friends is an array of users):

userSchema.set('toJSON', { hide: 'friends.password friends.salt' });

This will only affect the user.toJSON() call, the properties will still be accessible from your document like usual.

@lbeschastny

This comment has been minimized.

Show comment Hide comment
@lbeschastny

lbeschastny Oct 16, 2012

Contributor

@olalonde, I think it's a good solution.
I can see the only way to make your solution better, it's to allow this options to be overwritten during toJSON call.

I mean something like this:

user.toJSON()

uses default hide options, defined on schema level.

user.toJSON({hide: 'email'})

uses overwritten options.

But I'm not sure whether this call should hide email field only, or email and all default-hidden fields. But I'm sure that the option to hide some additional request-specific fields will be useful.

Contributor

lbeschastny commented Oct 16, 2012

@olalonde, I think it's a good solution.
I can see the only way to make your solution better, it's to allow this options to be overwritten during toJSON call.

I mean something like this:

user.toJSON()

uses default hide options, defined on schema level.

user.toJSON({hide: 'email'})

uses overwritten options.

But I'm not sure whether this call should hide email field only, or email and all default-hidden fields. But I'm sure that the option to hide some additional request-specific fields will be useful.

@olalonde

This comment has been minimized.

Show comment Hide comment
@olalonde

olalonde Oct 17, 2012

Contributor

I just checked Rails ActiveModel, and they use .as_json(:except => [:password, :salt]) or .as_json(:only => [:username, :password] (you can also override the default .as_json in your schema definition).

Also, I like the idea of adding hidden field when the call toJSON is made like @lbeschastny mentioned. If you don't want to use the behavior defined in your schema, maybe we should have a toJSONBypass method that takes the same options as toJSON but ignores the options set in the schema.

Contributor

olalonde commented Oct 17, 2012

I just checked Rails ActiveModel, and they use .as_json(:except => [:password, :salt]) or .as_json(:only => [:username, :password] (you can also override the default .as_json in your schema definition).

Also, I like the idea of adding hidden field when the call toJSON is made like @lbeschastny mentioned. If you don't want to use the behavior defined in your schema, maybe we should have a toJSONBypass method that takes the same options as toJSON but ignores the options set in the schema.

aheckmann added a commit that referenced this issue Oct 18, 2012

added; custom toObject/JSON formatting support
If an option for toObject/toJSON is a function, execute it
passing the current document, the object being returned from
toObject/toJSON, and the options specified. This allows users
to fully customize the formatting of their objects as well as
hide properties they want, etc.

Example:

  function format (mongooseDocument, objectReturned, options) {
    // perform formatting on based on the document
    // and/or options passed to toObject/JSON which default
    // to the options specified in the schema.
    if (options.hidden && 'string' == typeof options.hidden) {
      // apply custom property to `objectReturned` here
    }
  }

  new Schema({..}, { toJSON: { hide: format, hidden: 'some props' } }

  doc.toObject({ hidden: 'just these.props' })

See #1160, #1020
@aheckmann

This comment has been minimized.

Show comment Hide comment
@aheckmann

aheckmann Oct 18, 2012

Collaborator

this is a good idea, yet i think we might be thinking a little to fine grained here. instead of adding more custom formatting functionality directly to mongoose it might make sense to open it up to optionally apply any user driven formatting you want. that way we can still package up #1160 as a plugin as well as open the door for anyone to format objects how they want.

here's what i'm thinking: 82e1418

Collaborator

aheckmann commented Oct 18, 2012

this is a good idea, yet i think we might be thinking a little to fine grained here. instead of adding more custom formatting functionality directly to mongoose it might make sense to open it up to optionally apply any user driven formatting you want. that way we can still package up #1160 as a plugin as well as open the door for anyone to format objects how they want.

here's what i'm thinking: 82e1418

aheckmann added a commit that referenced this issue Oct 26, 2012

added; custom toObject/JSON formatting support
If an option for toObject/toJSON is a function, execute it
passing the current document, the object being returned from
toObject/toJSON, and the options specified. This allows users
to fully customize the formatting of their objects as well as
hide properties they want, etc.

Example:

  function format (mongooseDocument, objectReturned, options) {
    // perform formatting on based on the document
    // and/or options passed to toObject/JSON which default
    // to the options specified in the schema.
    if (options.hidden && 'string' == typeof options.hidden) {
      // apply custom property to `objectReturned` here
    }
  }

  new Schema({..}, { toJSON: { hide: format, hidden: 'some props' } }

  doc.toObject({ hidden: 'just these.props' })

See #1160, #1020
@aheckmann

This comment has been minimized.

Show comment Hide comment
@aheckmann

aheckmann Oct 26, 2012

Collaborator

since this functionality is easily doable as a plugin, lets leave this in user land.

Collaborator

aheckmann commented Oct 26, 2012

since this functionality is easily doable as a plugin, lets leave this in user land.

@aheckmann aheckmann closed this Oct 26, 2012

@chovy

This comment has been minimized.

Show comment Hide comment
@chovy

chovy Oct 26, 2012

This might help, you can hide fields with

Item.find().populate('created_by', '-salt -password_hash').exec(fn);

Assuming 'created_by' references a user schema.

chovy commented Oct 26, 2012

This might help, you can hide fields with

Item.find().populate('created_by', '-salt -password_hash').exec(fn);

Assuming 'created_by' references a user schema.

@mrzafod

This comment has been minimized.

Show comment Hide comment
@mrzafod

mrzafod Oct 26, 2012

@chovy, it's not a solution unfortunately. Because usually I have to select all fields, but need to make a json-object with just some of them

mrzafod commented Oct 26, 2012

@chovy, it's not a solution unfortunately. Because usually I have to select all fields, but need to make a json-object with just some of them

@lbeschastny

This comment has been minimized.

Show comment Hide comment
@lbeschastny

lbeschastny Oct 26, 2012

Contributor

@chovy, back-end usually requires more data than front-end.
It's not a problem to select from db only what you need.
The problem is to remove server-specific data before sending it to the client.

Contributor

lbeschastny commented Oct 26, 2012

@chovy, back-end usually requires more data than front-end.
It's not a problem to select from db only what you need.
The problem is to remove server-specific data before sending it to the client.

@mrzafod

This comment has been minimized.

Show comment Hide comment
@mrzafod

mrzafod Oct 26, 2012

@olalonde

This comment has been minimized.

Show comment Hide comment
@olalonde

olalonde Oct 26, 2012

Contributor

Until this is implemented in Mongoose, I have released this standalone utility function:

https://github.com/olalonde/jsonselect

You can also use my fork of Mongoose but it won't get merged. LearnBoost#1160

Contributor

olalonde commented Oct 26, 2012

Until this is implemented in Mongoose, I have released this standalone utility function:

https://github.com/olalonde/jsonselect

You can also use my fork of Mongoose but it won't get merged. LearnBoost#1160

@aheckmann

This comment has been minimized.

Show comment Hide comment
@aheckmann

aheckmann Oct 26, 2012

Collaborator

@olalonde cool. check out the plugins page. it should be pretty straightforward to allow people to specify which properties they want hidden by overriding Schema.methods.toJSON. Here's a start: https://gist.github.com/3959722

Collaborator

aheckmann commented Oct 26, 2012

@olalonde cool. check out the plugins page. it should be pretty straightforward to allow people to specify which properties they want hidden by overriding Schema.methods.toJSON. Here's a start: https://gist.github.com/3959722

@aheckmann

This comment has been minimized.

Show comment Hide comment
@aheckmann

aheckmann Nov 8, 2012

Collaborator

ok so we have something related coming here.

feedback welcome.

Collaborator

aheckmann commented Nov 8, 2012

ok so we have something related coming here.

feedback welcome.

aheckmann added a commit that referenced this issue Nov 8, 2012

support generic toJSON/toObject transforms
Calling doc.toObject() or doc.toJSON() now applies an optional
transform before returning the resulting document. Useful when
excluding document properties or complex reformatting is
necessary when JSON.stringifying a document etc.

The transform is either passed inline during execution:

    doc.toJSON({ transform: someFunction })

or is set in the schema options:

    schema.options.toJSON = { transform: someFunction }

Note that all schema options are overridden when passed inline,
so calling the following will result in no tranform applied:

    doc.toObject({ getters: true })

However, passing `transform: true` will apply it anyway:

    doc.toObject({ getters: true, tranform: true })

Closes #1197
Relates to #1020
Relates to #1160
@aheckmann

This comment has been minimized.

Show comment Hide comment
@aheckmann

aheckmann Nov 8, 2012

Collaborator

the relevant commit: 1161f79

Collaborator

aheckmann commented Nov 8, 2012

the relevant commit: 1161f79

@yichen

This comment has been minimized.

Show comment Hide comment
@yichen

yichen Nov 22, 2012

I end up using the underscoreJS, something like:
_.omit(doc.toJSON(), ['secret', 'hidden'])

yichen commented Nov 22, 2012

I end up using the underscoreJS, something like:
_.omit(doc.toJSON(), ['secret', 'hidden'])

@nkzawa

This comment has been minimized.

Show comment Hide comment
@nkzawa

nkzawa Mar 16, 2013

I wrote a plugin for this purpose.

https://github.com/nkzawa/mongoose-json-select

nkzawa commented Mar 16, 2013

I wrote a plugin for this purpose.

https://github.com/nkzawa/mongoose-json-select

@alexcason

This comment has been minimized.

Show comment Hide comment
@alexcason

alexcason Apr 22, 2013

This issue is still causing trouble for me. I've defined default behaviour in toJSON on each of my models and I could even pass arguments into it which would allow me to change which fields are selected in different circumstances.

Embedded documents are more difficult though, as there is no straightforward way to pass in the desired options without deconstructing the document and putting it back together again. The same is true of document collections, albeit to a lesser extent. I'd need to loop through every document in the collection, calling toJSON along with my arguments and then reconstruct the JSON to be sent in the response.

This issue is still causing trouble for me. I've defined default behaviour in toJSON on each of my models and I could even pass arguments into it which would allow me to change which fields are selected in different circumstances.

Embedded documents are more difficult though, as there is no straightforward way to pass in the desired options without deconstructing the document and putting it back together again. The same is true of document collections, albeit to a lesser extent. I'd need to loop through every document in the collection, calling toJSON along with my arguments and then reconstruct the JSON to be sent in the response.

@pfzero

This comment has been minimized.

Show comment Hide comment
@pfzero

pfzero Aug 11, 2013

Do I need to rewrite the toJSON method using the schema.options.transform function? I've tried this but it seems that after deleting some attributes from document and returning it from my transform function, the toJSON method returns all the attributes related to mongoose schema. Can you give an example of correctly defining transform function? Thanks.

pfzero commented Aug 11, 2013

Do I need to rewrite the toJSON method using the schema.options.transform function? I've tried this but it seems that after deleting some attributes from document and returning it from my transform function, the toJSON method returns all the attributes related to mongoose schema. Can you give an example of correctly defining transform function? Thanks.

@pfzero

This comment has been minimized.

Show comment Hide comment
@pfzero

pfzero Aug 11, 2013

Ok, I made it working with the following code (it's seems like a workaround though):

schema.options.toJSON = {
transform: function(userDocument) {
var doc = userDocument.toJSON({transform: false});
delete doc.password;
delete doc.salt;
delete doc.__v;
return doc;
}
}

Is this a correct usage, or am I missing something?
ty

pfzero commented Aug 11, 2013

Ok, I made it working with the following code (it's seems like a workaround though):

schema.options.toJSON = {
transform: function(userDocument) {
var doc = userDocument.toJSON({transform: false});
delete doc.password;
delete doc.salt;
delete doc.__v;
return doc;
}
}

Is this a correct usage, or am I missing something?
ty

@martindale

This comment has been minimized.

Show comment Hide comment
@martindale

martindale Nov 29, 2013

Is there documentation or an example somewhere of how to use the code @aheckmann introduced in 1161f79?

Is there documentation or an example somewhere of how to use the code @aheckmann introduced in 1161f79?

@b52

This comment has been minimized.

Show comment Hide comment
@b52

b52 Jan 2, 2014

@martindale I use it like this, with User being my scheme and hash and salt two fields I want to hide:

User.options.toJSON = {
  transform: function(user) {
    delete user.hash;
    delete user.salt;
  }
};

b52 commented Jan 2, 2014

@martindale I use it like this, with User being my scheme and hash and salt two fields I want to hide:

User.options.toJSON = {
  transform: function(user) {
    delete user.hash;
    delete user.salt;
  }
};
@KuzminDima

This comment has been minimized.

Show comment Hide comment
@KuzminDima

KuzminDima Mar 21, 2014

  UserSchema.method('toJSON', function() {
    var user = this.toObject();
    delete user.salt;
    delete user.hash;
    delete user.__v;
    return user;
  });
  UserSchema.method('toJSON', function() {
    var user = this.toObject();
    delete user.salt;
    delete user.hash;
    delete user.__v;
    return user;
  });
@paulwalker

This comment has been minimized.

Show comment Hide comment
@paulwalker

paulwalker Jun 1, 2016

Is there any capability to create a transformation function that is applied to all schemas? And/or is there a capability to hide fields out of the box w/out needing to define your own transform function?

Is there any capability to create a transformation function that is applied to all schemas? And/or is there a capability to hide fields out of the box w/out needing to define your own transform function?

@vkarpov15

This comment has been minimized.

Show comment Hide comment
@vkarpov15

vkarpov15 Jun 1, 2016

Collaborator

@paulwalker write a plugin. You can then apply your plugin to all schemas using mongoose.plugin()

Collaborator

vkarpov15 commented Jun 1, 2016

@paulwalker write a plugin. You can then apply your plugin to all schemas using mongoose.plugin()

@paulwalker

This comment has been minimized.

Show comment Hide comment
@paulwalker

paulwalker Jun 1, 2016

That doesn't seem to work with options as it does with methods and statics.

That doesn't seem to work with options as it does with methods and statics.

@vkarpov15

This comment has been minimized.

Show comment Hide comment
@vkarpov15

vkarpov15 Jun 1, 2016

Collaborator

Can you clarify? I don't quite understand your comment.

Collaborator

vkarpov15 commented Jun 1, 2016

Can you clarify? I don't quite understand your comment.

@paulwalker

This comment has been minimized.

Show comment Hide comment
@paulwalker

paulwalker Jun 1, 2016

Meaning, this did not work for me:

mongoose.plugin(function (schema, options) {
  schema.options.toJSON = { transform: function() { ... } }
})

adding to schema.methods works, adding to schema.statics works...

hmmm, do i need to instead modify the options argument?

paulwalker commented Jun 1, 2016

Meaning, this did not work for me:

mongoose.plugin(function (schema, options) {
  schema.options.toJSON = { transform: function() { ... } }
})

adding to schema.methods works, adding to schema.statics works...

hmmm, do i need to instead modify the options argument?

@paulwalker

This comment has been minimized.

Show comment Hide comment
@paulwalker

paulwalker Jun 2, 2016

No, that is not the solution I see...the options get passed in when registering the plugin itself, which is only really useful for plugins that are used on a model by model basis.

My schema is for a sub-document, so I am exploring that as the potential issue.

No, that is not the solution I see...the options get passed in when registering the plugin itself, which is only really useful for plugins that are used on a model by model basis.

My schema is for a sub-document, so I am exploring that as the potential issue.

@vkarpov15

This comment has been minimized.

Show comment Hide comment
@vkarpov15

vkarpov15 Jun 4, 2016

Collaborator

Can you show me your schema and the contents of your transform function? I'd like to try to repro but right now I'd just be taking a shot in the dark because we have tests in place for that type of thing and they work.

Collaborator

vkarpov15 commented Jun 4, 2016

Can you show me your schema and the contents of your transform function? I'd like to try to repro but right now I'd just be taking a shot in the dark because we have tests in place for that type of thing and they work.

@isaachinman

This comment has been minimized.

Show comment Hide comment
@isaachinman

isaachinman Mar 15, 2018

For anyone arriving at this thread in the future, there's a nice plugin called mongoose-private-paths that seems to be used somewhat widely.

For anyone arriving at this thread in the future, there's a nice plugin called mongoose-private-paths that seems to be used somewhat widely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment