【问题标题】:Mongoose: what's up with "_doc"?Mongoose:“_doc”怎么了?
【发布时间】:2013-09-20 04:49:49
【问题描述】:

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

var Foo = new mongoose.model('Foo', new mongoose.Schema({a: String, b: Number}));
var foo = new Foo({a: 'test'; b: 42}); 
var obj = {c: 1};
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

console.log(foo.goo === obj);   // comparison directly after the assignment
    // => false, doesn't behave like normal JS object

基本上,任何时候您尝试处理 Mongoose 模型的属性时都不是

a) 在模型的架构中定义或

b) 定义为相同类型(数组、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});
});

【问题讨论】:

  • goo 是一个字符串,但你在值中放入了一个对象?
  • @WiredPrairie 我已经重写以更好地说明怪异
  • 我仍然无法复制您在第一个示例中遇到的问题。你用的是什么版本的 NodeJS 和 mongo?
  • 在第二个示例中添加了更多细节。
  • @Colin 看起来答案不再符合您的问题了,您有没有弄清楚为什么 ._doc 存在/为什么来自 Mongoose 的文档的行为不像我们期望的 javascript 对象那样?

标签: node.js mongodb mongoose


【解决方案1】:

更新

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

我测试了你的代码,它对我来说很好用。当您设置不属于架构的属性(或其他一些特殊属性)时,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 作为转换的一部分传递的数据。

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

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

【讨论】:

  • 对不起,我想我在你回复的时候编辑了这个问题:S
  • 是的,你做到了。 :) 我编辑了答案以反映您的新更改。
  • 啊,是的。我现在看清楚了。。雨已经过去了。感谢您的所有帮助;非常感谢!
【解决方案2】:

_doc 存在于 mongoose 对象上。

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

如果你尝试 JSON.stringify 之类的东西,那么你会看到 mongoose 模型对象的内部。 (_doc, state ...)

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

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

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

【讨论】:

  • 很好的解释兄弟。这正是我会知道的。非常感谢
  • 很好的解释。您能否指导我查看_doc 的一些文档,因为我自己在猫鼬文档中找不到它。谢谢。
【解决方案3】:

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

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

这解决了我的问题

【讨论】:

    【解决方案4】:

    尝试使用精益

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

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

    【讨论】:

      【解决方案5】:

      我今天被困在这个问题上……把我逼疯了。不确定以下是否是一个好的解决方案(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")传入模型中未定义的此属性,它将起作用(将分配此颜色属性到每辆车),但由于某种原因,您似乎无法通过 EJS(前端)访问它。

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

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

      重新定义模型后,一切正常/预期(不需要 _doc 'hacks' 等),我又活了一天;希望它可以帮助别人。

      【讨论】:

      【解决方案6】:

      你可以使用 toJSON() 代替 _doc

      【讨论】:

        【解决方案7】:

        Mongoose 模型有些奇怪,您必须检查 Mongoose 的模型数组中是否还没有创建模型。

        这是我的解决方案:

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

        我为我的模型使用自己的猫鼬模型类和基类。我做了这个,它应该适合你。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-22
          • 2020-07-01
          • 2015-06-29
          • 2012-09-05
          • 2021-06-21
          • 1970-01-01
          相关资源
          最近更新 更多