5

I have some information on my mongoose models which is transient. For performance reasons I dont wish to store it against the model.. But I do want to be able to provide this information to clients that connect to my server and ask for it.

Here's a simple example:

 var mongoose = require('mongoose'),
     db = require('./dbconn').dbconn;

 var PersonSchema = new mongoose.Schema({
  name    : String,
  age     : Number,
});

var Person = db.model('Person', PersonSchema);
var fred = new Person({ name: 'fred', age: 100 });

The Person schema has two attributes that I want to store (name, and age).. This works.. and we see in the console:

console.log(fred);

{ name: 'fred', age: 100, _id: 509edc9d8aafee8672000001 }

I do however have one attribute ("status") that rapidly changes and I dont want to store this in the database.. but I do want to track it dynamically and provide it to clients so I add it onto the instance as a key/val pair.

fred.status = "alive";

If we look at fred in the console again after adding the "alive" key/val pair we again see fred, but his status isnt shown:

{ name: 'fred', age: 100, _id: 509edc9d8aafee8672000001 }

Yet the key/val pair is definitely there.. we see that:

console.log(fred.status);

renders:

alive

The same is true of the JSON representation of the object that I'm sending to clients.. the "status" isnt included..

I dont understand why.. can anyone help?

Or, alternatively, is there a better approach for adding attributes to mongoose schemas that aren't persisted to the database?

Duncan_m
  • 2,526
  • 2
  • 21
  • 19
  • I think this is something quirky with mongoose objects. I always append user.avatar to be their gravatar url. – chovy Nov 10 '12 at 23:40

3 Answers3

9

Adding the following to your schema should do what you want:

PersonSchema.virtual('status').get(function() {
  return this._status;
});

PersonSchema.virtual('status').set(function(status) {
  return this._status = status;
});

PersonSchema.set('toObject', {
  getters: true
});

This adds the virtual attribute status - it will not be persisted because it's a virtual. The last part is needed to make your console log output correctly. From the docs:

To have all virtuals show up in your console.log output, set the toObject option to { getters: true }

Also note that you need to use an internal property name other than status (here I used _status). If you use the same name, you will enter an infinite recursive loop when executing a get.

David Weldon
  • 63,632
  • 11
  • 148
  • 146
  • 1
    You can call `toObject` on your instance before sending the data. I prefer to override `toJSON` as seen [here](https://groups.google.com/d/topic/mongoose-orm/SHe_Fsso_44/discussion). – David Weldon Nov 11 '12 at 03:59
  • 3
    You can also enable `getters` on `toJSON` as described [here](http://mongoosejs.com/docs/guide.html#toJSON) so that you don't have to override the method. – JohnnyHK Nov 12 '12 at 19:58
2

Simply call .toObject() on the data object.

For you code will be like:

fred.toObject()

Amol M Kulkarni
  • 21,143
  • 34
  • 120
  • 164
0

This has been very helpful. I had to struggle with this myself. In my case, I was getting a document from mongoose. When I added a new key, the key was not visible to the object if I console.log it. When I searched for the key (console.log(data.status), I could see it in the log but not visible if I logged the entire object.

After reading this response thread, it worked.

For example, I got an object like this one from my MongoDB call:

`Model.find({}).then(result=> {
    //console.log(result);// [{ name:'John Doe', email:'john@john.com'}];

    //To add another key to the result, I had to change that result like this:
    var d = result[0];
    var newData = d.toJSON();
    newData["status"] = "alive";
    console.log(newData);// { name:'John Doe', email:'john@john.com', status:'alive'};
}).catch(err=>console.log(err))`

Hope this helps someone else. HappyCoding

Baraka Mahili
  • 91
  • 3
  • 6