Mongoose/MongoDB result fields appear undefined in Javascript

tippenein picture tippenein · Sep 10, 2013 · Viewed 21.8k times · Source

Is there something that I'm missing that would allow item to log as an object with a parameter, but when I try to access that parameter, it's undefined?

What I've tried so far:

  • console.log(item) => { title: "foo", content: "bar" } , that's fine
  • console.log(typeof item) => object
  • console.log(item.title) => "undefined"

I'll include some of the context just in case it's relevant to the problem.

var TextController = function(myCollection) {
  this.myCollection = myCollection
}

TextController.prototype.list = function(req, res, next) {
  this.myCollection.find({}).exec(function(err, doc) {
    var set = new Set([])
    doc.forEach(function(item) {
      console.log(item)         // Here item shows the parameter
      console.log(item.title)   // "undefined"
      set.add(item.title)       
    })
    res.json(set.get());
  })
}

Based on suggestion I dropped debugger before this line to check what item actually is via the node repl debugger. This is what I found : http://hastebin.com/qatireweni.sm

From this I tried console.log(item._doc.title) and it works just fine.. So, this seems more like a mongoose question now than anything.

There are questions similar to this, but they seem to be related to 'this' accessing of objects or they're trying to get the object outside the scope of the function. In this case, I don't think I'm doing either of those, but inform me if I'm wrong. Thanks

Answer

Vincent Bel picture Vincent Bel · Apr 3, 2016

Solution

You can call the toObject method in order to access the fields. For example:

var itemObject = item.toObject();
console.log(itemObject.title); // "foo"

Why

As you point out that the real fields are stored in the _doc field of the document.

But why console.log(item) => { title: "foo", content: "bar" }?

From the source code of mongoose(document.js), we can find that the toString method of Document call the toObject method. So console.log will show fields 'correctly'. The source code is shown below:

var inspect = require('util').inspect;

...

/**
 * Helper for console.log
 *
 * @api public
 */
Document.prototype.inspect = function(options) {
  var isPOJO = options &&
    utils.getFunctionName(options.constructor) === 'Object';
  var opts;
  if (isPOJO) {
    opts = options;
  } else if (this.schema.options.toObject) {
    opts = clone(this.schema.options.toObject);
  } else {
    opts = {};
  }
  opts.minimize = false;
  opts.retainKeyOrder = true;
  return this.toObject(opts);
};

/**
 * Helper for console.log
 *
 * @api public
 * @method toString
 */

Document.prototype.toString = function() {
  return inspect(this.inspect());
};