Mongoose: what happened to "_doc"?

Mongoose seems to be doing something really cool inside.

1 var Foo = new mongoose.model('Foo', new mongoose.Schema({a: String, b: Number})); 2 var foo = new Foo({a: 'test; b: 42}); 3 var obj = {c: 1}; 4 foo.goo = obj; // simple object assignment. obj should be // passed by reference to foo.goo. recall goo // is not defined in the Foo model schema 5 console.log(foo.goo === obj); // comparison directly after the assignment // => false, does not behave like normal JS object 

Essentially, every time you try to figure out Mongoose model properties that are not

a) defined in the model diagram or

b) is defined as the same type (array, object, ..) ... the model does not even behave like a regular Javascript object.

Switching line 4 to foo._doc.goo = obj output true to the console.

edit : try to reproduce oddities

Example 1 :

  // Customer has a property 'name', but no property 'text' // I do this because I need to transform my data slightly before sending it // to client. models.Customer.find({}, function(err, data) { for (var i=0, len=data.length; i<len; ++i) { data[i] = data[i]._doc; // if I don't do this, returned data // has no 'text' property data[i].text = data[i].name; } res.json({success: err, response:data}); }); 
+13
mongodb mongoose
source share
3 answers

Update

Perhaps I misunderstood your initial question, but now it seems that the nature of your question has changed, so the information below is not relevant, but I leave it. :)

I checked your code and it works great for me. Mongoose does not execute any special code when you set properties that are not part of the schema (or several other special properties). JavaScript currently does not support calling code for properties that do not yet exist (therefore, Mongoose cannot interfere, for example, with a set of goo properties).

So, when you set the property:

 foo.goo = { c: 1 }; 

Mongoose is not involved. If your console.log was something different from the code you displayed, I could see that it might report incorrectly.

Also, when you send return the results as JSON, JSON.stringify is JSON.stringify , which calls toString for your Mongoose model. When this happens, Mongoose uses only the properties defined in the schema. Thus, no additional properties are sent back by default. You changed the nature of the data array to directly point to Mongoose data, so it avoids this problem.

Normal behavior details

When you set the goo property using Mongoose, quite a few things happen. Mongoose creates tools for getting / setting properties using Object.defineProperty (some documents ). So, when you set the goo property that you defined as [String] , several things happen:

  1. Mongoose code is called before setting the value to an instance of the object (as opposed to a simple JavaScript object)
  2. Mongoose creates an array (optional) to store data ( MongooseArray ) that will contain the data in the array. In the example you provided, since you did not pass the array, it will be created.
  3. Mongoose will try to cast your data to the desired type
  4. It will call toString for the data passed as part of the cast.

Thus, as a result, the document now contains an array with a toString version of the object you submitted.

If you checked the contents of the goo property, you will see that now it is an array with one element, which is a string containing [object Object] . If you select a more basic type or match the storage type of the target property, you would see that a basic equality check would work.

+5
source share

I'm stuck on this today ... driving me crazy. Not sure if the following is a good solution (and the OP mentioned it too), but I solved this problem.

My car object:

  cars = [{"make" : "Toyota"}, {"make" : "Kia"}]; 

Act:

 console.log("1. Cars before the color: " + car); cars.forEach(function(car){ car.colour = "Black"; //color is NOT defined in the model. }); console.log("2. Cars after the color: " + car); 

Problem output to the console:

  1. Cars before the color: [{"make" : "Toyota"}, {"make" : "Kia"}]; 2. Cars after the color: [{"make" : "Toyota"}, {"make" : "Kia"}]; //No change! No new colour properties :( 

If you try to pass this property, which was not defined in the model, through the document (for example, car. _Doc .color = "black"), it will work (this color property will be assigned to each car), but you won’t be able to that access to it through EJS (interface) for some reason.

Solution : (Again, not sure if this is the best way ... but it worked for me): Add a new property (color) to the car model.

 var carSchema = mongoose.Schema({ make: String, color: String //New property. }) 

After redefining the model, everything worked as usual / expected (no β€œhacks”, etc. are needed), and I lived one more day; hope this helps someone else.

0
source share

There are some oddities with Mongoose models, and you need to make sure that Mongoose does not yet have a model created in the model array.

Here is my solution:

 import mongoose from 'mongoose'; createModel = (modelName="foo", schemaDef, schemaOptions = {})=> { const { Schema } = mongoose; const schema = Schema(schemaDef, schemaOptions); const Model = mongoose.models[modelName] || mongoose.model(modelName, schema); return Model; } 

I use my own mongoose model class and base class for my models. I did it, and it should work for you.

0
source share

All Articles