猫鼬:怎么了"_doc"?

Col*_*lin 14 mongoose mongodb node.js

似乎Mongoose在内部做了一些非常时髦的事情.

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, doesn't behave like normal JS object
Run Code Online (Sandbox Code Playgroud)

基本上,任何时候你试图处理Mongoose模型的属性,而不是a)在模型的模式中定义或b)被定义为相同的类型(array,obj,..)......模型甚至都没有表现得像一个普通的Javascript对象.

切换第4行以foo._doc.goo = obj进行控制台输出true.

编辑:试图重现怪异

例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});
});
Run Code Online (Sandbox Code Playgroud)

ent*_*sar 8

您可以使用 toJSON() 而不是 _doc


Usa*_*din 6

_doc存在于猫鼬对象上。

由于mongooseModel.findOne返回模型本身,因此模型具有结构(受保护的字段)。当您尝试使用 console.log 打印对象时,它只会为您提供数据库中的数据,因为 console.log 将打印对象公共字段。

如果你尝试像 JSON.stringify 这样的东西,那么你就会看到猫鼬模型对象的内部。(_doc,状态...)

如果您想在对象中添加更多字段并且它不起作用

const car = model.findOne({_id:'1'})
car.someNewProp = true // this will not work
Run Code Online (Sandbox Code Playgroud)

如果稍后您将该属性设置为对象 car 并且您之前没有在模型架构中指定,则 Mongoose 模型将验证此字段是否存在以及它是否为有效类型。如果验证失败,则不会设置该属性。


Wir*_*rie 5

更新资料

也许我误解了您的原始问题,但是现在看来您问题的性质发生了变化,因此以下信息无关紧要,但我将其保留。:)

我测试了您的代码,对我来说很好。当您设置不属于架构的属性(或其他一些特殊属性)时,Mongoose不会执行任何特殊代码。JavaScript当前不支持为尚不存在的属性调用代码(例如,Mongoose不会妨碍该goo属性集)。

因此,当您设置属性时:

foo.goo = { c: 1 };
Run Code Online (Sandbox Code Playgroud)

猫鼬不参与其中。如果您console.log的代码不是您显示的代码,则可能会报告错误。

另外,当您send将结果返回为JSON时,JSON.stringify将被调用,这将toString在您的Mongoose模型上调用。发生这种情况时,Mongoose仅使用在架构上定义的属性。因此,默认情况下不会发送任何其他属性。您已经更改了data数组的性质,但是可以直接指向Mongoose数据,因此可以避免该问题。

有关正常行为的详细信息

当您goo使用Mongoose 设置属性时,会发生很多事情。猫鼬通过Object.defineProperty(一些文档)创建属性获取器/设置器。因此,当您将goo属性定义[String]为时,会发生一些事情:

  1. 在将值设置到对象实例之前会调用猫鼬代码(与简单的JavaScript对象不同)
  2. 猫鼬创建一个数组(可选)来存储MongooseArray将包含数组数据的数据(a )。在您提供的示例中,由于未传递数组,因此将创建该数组。
  3. 猫鼬会尝试将您的数据转换为正确的类型
  4. 它将调用toString作为强制转换的一部分传递的数据。

因此,结果是该文档现在包含一个数组,其中包含toString您传递的对象的版本。

如果检查了goo属性的内容,您会发现它现在是一个具有单个元素的数组,该元素是一个包含的字符串[object Object]。如果选择了更基本的类型或与目标属性存储类型匹配,则将看到基本的相等性检查将起作用。