猫鼬:什么" _doc"?

时间:2013-09-16 05:54:54

标签: node.js mongodb mongoose

似乎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

基本上,每次尝试处理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});
});

6 个答案:

答案 0 :(得分:4)

更新

也许我误解了你原来的问题,但是现在看来问题的性质发生了变化,所以下面的信息并不重要,但我要离开了。 :)

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

所以,当你设置属性时:

foo.goo = { c: 1 };

不涉及猫鼬。如果您的console.log不是您显示的代码,我可能会看到它可能报错。

此外,当您将结果send作为JSON返回时,系统会调用JSON.stringify,在您的Mongoose模型上调用toString。发生这种情况时,Mongoose仅使用模式中定义的属性。因此,默认情况下不会发送任何其他属性。您已经改变了data数组的性质,直接指向Mongoose数据,因此它避免了这个问题。

有关正常行为的详细信息

使用Mongoose设置属性goo时,会发生很多事情。 Mongoose通过Object.defineProperty(一些docs)创建属性getter / setter。因此,当您设置goo属性时,您已定义为[String],会发生以下情况:

  1. 在将值设置到对象实例之前调用Mongoose代码(与简单的JavaScript对象不同)
  2. Mongoose创建一个数组(可选)来存储将包含数组数据的数据(MongooseArray)。在您提供的示例中,由于您未传递数组,因此将创建它。
  3. Mongoose会尝试将您的数据转换为正确的类型
  4. 它会调用toString作为演员阵容传递的数据。
  5. 因此,结果是文档现在包含一个数组,其中包含您传递的对象的toString版本。

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

答案 1 :(得分:2)

_doc 存在于猫鼬对象上。

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

如果尝试使用JSON.stringify之类的方法,则会看到猫鼬模型对象内部。 (_doc,状态...)

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

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

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

答案 2 :(得分:1)

有同样的问题。而不是更新我的模型。

const car = model.findOne({_id:'1'})
let temp = JSON.stringify(car);
let objCar = JSON.parse(temp);
objCar.color = 'Red'; //now add any property you want

这解决了我的问题

答案 3 :(得分:0)

我今天被困住了……让我发疯。不知道下面是否是一个好的解决方案(OP也提到了),但这就是我克服了这个问题的方法。

我的汽车对象:

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

操作:

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);

问题控制台输出:

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

如果您尝试通过doc(例如car。 _doc .color =“ black”)传递模型中未定义的此属性,则它将起作用(将分配此color属性)到每辆汽车),但您似乎由于某种原因无法通过EJS(前端)进行访问。

解决方案: (再次,不确定这是否是最好的方法...但是对我有用):在汽车模型中添加这个新属性(颜色)。

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

重新定义模型后,一切都按正常/预期的方式进行(不需要_doc'hacks'等),我又住了一天;希望对别人有帮助。

答案 4 :(得分:0)

Mongoose模型有些奇怪,您必须检查Mongoose的modelss数组中尚未创建模型。

这是我的解决方法:

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;
}

我为模型使用自己的猫鼬模型类和基类。我做到了,它应该为您工作。

答案 5 :(得分:0)

尝试使用精益

<块引用>

默认情况下,Mongoose 查询返回一个 Mongoose Document 类的实例。文档比普通的 JavaScript 对象重得多,因为它们有很多内部状态用于更改跟踪。启用精简选项会告诉 Mongoose 跳过实例化完整的 Mongoose 文档,而只为您提供 POJO。

https://mongoosejs.com/docs/tutorials/lean.html