Why mongoose replaces subdocuments with "[object Object]"?

I'm encountering weird behavior with embedded docs and I don't know if I do something wrong or is it a bug.

This is my model:

var mg = require('mongoose')
 , S  = mg.Schema;

var subject = new S({
    name: String
  , properties: [{
        name: String
      , value: String
    }]
});

module.exports = mg.model('Subject',subject);

When I try to add a property, it somehow gets converted into "[object Object]":

  console.log(req.body); // --> { name: 'height', value: 120 }
  console.log(typeof req.body); // --> object
  ob.Subject.findByIdAndUpdate(req.params.id, {$push: {properties: req.body}}, function(err, doc) {
    if(err) throw err;
    res.send(doc);
  });

The returned doc is:

{_id: '...', name: 'sss', properties:[ "[object Object]" ]}

I used mongo CLI to inspect the document in the database and put proper values in it.

//the document as seen in mongo CLI:
{
  _id: '...', name: 'sss', 
  properties: [ "[object Object]", {name: "aaa", value: "bar"} ]
}

Then I tried this:

ob.Subject.findById(id, function(err, doc) {
  res.send(doc);
}

And then the returned doc is:

{ 
  _id: '...', name: 'sss', 
  properties:[ "[object Object]", "[object Object]" ]
}

I think that, what's happening is mongoose somehow converts the subdocument into this string. Moreover, I don't think that this is my, or res.send() fault because:

  • I'm not using toJson or toObject explicitly, I don't handle JSON conversion at all
  • res.send() is not an issue because even if I util.inspect the value - it's the same
  • invalid conversion seems to happen both at write and read via mongoose

Have you ever encountered similar behavior? Is there a way around that?

I just started with mongoose and don't have an idea how to fallback to mongodb native to update and fetch documents and check if this behavior persists (I doubt).

Any helpful hints appreciated :)

Even though Node.js and MongoDB both use Javascript they do not share the same memory space. They're not even running in the same process. Thus they have to talk over tcp and serialize data.

I would assume your req.body is getting toString()'ed when formatting the request for mongoDB.

EDIT

This is normal because you declared the prepoerties attribute of your model as an array of strings.

Just declare it:

properties: Object

I think your 'properties' property is defined wrong. I understand what you are trying to do, but I suspect you need to define the key/value pair as a type of it's own so that your code becomes:

    var mg = require('mongoose')
     , S  = mg.Schema;

    var keyValue = new S({
        key: String, value: String});

    var subject = new S({
        name: String
      , properties: [keyValue]
    });

    module.exports = mg.model('Subject',subject);

You could try this:

ob.Subject.findByIdAndUpdate(req.params.id, {$push: {properties: {name: req.body.name, value: req.body.value}}}, function(err, doc) {
    if(err) throw err;
    res.send(doc);
});