【问题标题】:Mongoose/MongoDB result fields appear undefined in JavascriptMongoose/MongoDB 结果字段在 Javascript 中显示为未定义
【发布时间】:2013-09-13 15:20:27
【问题描述】:

是否有什么我遗漏的东西可以让项目记录为带有参数的对象,但是当我尝试访问该参数时,它是未定义的?

到目前为止我已经尝试过:

  • console.log(item) => { title: "foo", content: "bar" } 没关系
  • console.log(typeof item) => 对象
  • console.log(item.title) => “未定义”

我将包含一些上下文,以防它与问题相关。

var TextController = function(myCollection) {
  this.myCollection = myCollection
}

TextController.prototype.list = function(req, res, next) {
  this.myCollection.find({}).exec(function(err, doc) {
    var set = new Set([])
    doc.forEach(function(item) {
      console.log(item)         // Here item shows the parameter
      console.log(item.title)   // "undefined"
      set.add(item.title)       
    })
    res.json(set.get());
  })
}

根据建议,我在此行之前删除了debugger,以通过节点 repl 调试器检查实际是什么项目。这是我发现的:http://hastebin.com/qatireweni.sm

从这里我尝试了console.log(item._doc.title),它工作得很好。所以,现在这似乎更像是一个猫鼬问题。

有与此类似的问题,但它们似乎与对象的“this”访问有关,或者他们试图使对象超出函数的范围。在这种情况下,我不认为我在做任何一个,但如果我错了,请告诉我。谢谢

【问题讨论】:

    标签: javascript mongodb mongoose javascript-objects function-prototypes


    【解决方案1】:

    tue查询时,使用.lean() E.g

    const order = await Order.findId("84578437").lean()
    

    【讨论】:

      【解决方案2】:

      如果您只想获取没有猫鼬所有好处的信息,请保存,即您可以在查询中使用 .lean()。它将更快地获取您的信息,您可以直接将其用作对象。

      https://mongoosejs.com/docs/api.html#query_Query-lean

      正如文档中所说,这是最好的只读方案。

      【讨论】:

        【解决方案3】:

        解决此类问题的更好方法是像这样使用doc.toObject()

        doc.toObject({ getters: true })
        

        其他选项包括:

        • getters: 应用所有 getter(路径和虚拟 getter)
        • virtuals: 应用虚拟吸气剂(可以覆盖吸气剂选项)
        • minimize:删除空对象(默认为true)
        • transform: 在返回之前应用于结果文档的转换函数
        • depopulate: 删除所有填充的路径,用它们的原始引用替换它们(默认为 false)
        • versionKey:是否包含版本密钥(默认为true)

        例如你可以说

        Model.findOne().exec((err, doc) => {
           if (!err) {
              doc.toObject({ getters: true })
              console.log('doc _id:', doc._id) // or title
           }
        })
        

        现在它可以工作了

        【讨论】:

          【解决方案4】:

          使用findOne() 而不是find()

          find() 方法返回一个值数组,即使您只有一个可能的结果,您也需要使用 item[0] 来获取它。

          findOne 方法返回一个对象或不返回任何对象,然后您就可以毫无问题地访问其属性。

          【讨论】:

          • 就是这样,谢谢!!!没有注意到我正在处理一个数组!
          【解决方案5】:

          解决方案

          您可以调用toObject 方法来访问这些字段。例如:

          var itemObject = item.toObject();
          console.log(itemObject.title); // "foo"
          

          为什么

          正如您所指出的,真正的字段存储在文档的_doc 字段中

          但是为什么console.log(item) => { title: "foo", content: "bar" }

          the source code of mongoose(document.js)可以发现DocumenttoString方法调用了toObject方法。所以console.log 将“正确”显示字段。源码如下图:

          var inspect = require('util').inspect;
          
          ...
          
          /**
           * Helper for console.log
           *
           * @api public
           */
          Document.prototype.inspect = function(options) {
            var isPOJO = options &&
              utils.getFunctionName(options.constructor) === 'Object';
            var opts;
            if (isPOJO) {
              opts = options;
            } else if (this.schema.options.toObject) {
              opts = clone(this.schema.options.toObject);
            } else {
              opts = {};
            }
            opts.minimize = false;
            opts.retainKeyOrder = true;
            return this.toObject(opts);
          };
          
          /**
           * Helper for console.log
           *
           * @api public
           * @method toString
           */
          
          Document.prototype.toString = function() {
            return inspect(this.inspect());
          };
          

          【讨论】:

          • 在 Mongo 3.2 上对我不起作用。说它没有toObject 方法。
          • @GeorgeRappel 通过引用Automattic/mongooseHistory,在3.4.0 版本中添加了toObject。 mongoose 的最新版本是 4.5.2。我认为您需要更新您的猫鼬模块...
          • 我有 moongose 版本 4.8.4 并且收到相同的消息错误:“TypeError: user.toObject is not a function”
          • 如果我这样做 toObject 我可以使用 obj (foo) 作为猫鼬对象,例如foo.save() ?我在查询 mongoose 时使用 .lean() 解决了这个问题
          【解决方案6】:

          老问题,但由于我也有这个问题,所以我会回答它。
          这可能是因为您使用的是find() 而不是findOne()。所以最后,你调用的是一个文档数组而不是文档的方法,导致找到一个数组而不是单个文档。使用findOne() 可以让您正常访问该对象。

          【讨论】:

            【解决方案7】:

            确保您已在架构中定义标题:

            var MyCollectionSchema = new mongoose.Schema({
                _id: String,
                title: String
            });
            

            【讨论】:

            • 这是我的问题!!!该文档在数据库中是正确的,但由于架构不正确,即使它正确打印了整个对象,它也不会显示变量。
            【解决方案8】:

            我认为使用 'find' 方法会返回一个文档数组。我尝试了这个并且能够打印标题

            for (var i = 0; i < doc.length; i++) {
               console.log("iteration " + i);
               console.log('ID:' + docs[i]._id);
               console.log(docs[i].title);
            }
            

            【讨论】:

              【解决方案9】:

              尝试在item 上执行for in 循环,看看是否可以访问值。

              for (var k in item) {
                  console.log(item[k]);
              }
              

              如果有效,则意味着您的密钥有一些 non-printable 字符或类似的字符。

              从您在 cmets 中所说的来看,item 似乎是 String 原始包装器的一个实例。

              例如

              var s = new String('test');
              typeof s; //object
              s instanceof String; //true
              

              要验证这个理论,试试这个:

              eval('(' + item + ')').title;
              

              也可能是item 是一个具有toString 方法的对象,可以显示您所看到的内容。

              编辑:要快速识别这些问题,您可以使用console.dir 而不是console.log,因为它会显示对象属性的交互式列表。您还可以设置断点并添加监视。

              【讨论】:

              • 是的!有点。除非我这样做,否则它将对象作为字符串返回。前"{ title: 'foo'\n content: 'bar'}"
              • 您的意思是console.log(item[k]) 显示您所说的内容?
              • 它将项目显示为字符串,这使得对象的参数无法访问。我更新了这个问题,以更好地描述我对正在发生的事情的了解。
              • @tippenein,我更新了答案,以便您了解您得到的结果。我希望该对象具有用于打印自身的自定义 toString 函数。这可以解释混乱。
              • 我很欣赏这些解释,但从我最近的发现来看,item._doc.title 会返回我所期望的。这证实了它是一个对象,但它以某种方式无法打印出它实际包含的内容。
              【解决方案10】:

              你在初始化你的对象吗?

              function MyObject()
              {
                  this.Title = "";
                  this.Content = "";
              }
              
              var myo1 = new MyObject();
              

              如果您没有初始化或没有设置标题。你会得到未定义的。

              【讨论】:

              • 对象由 mongoose collection.find({}) 返回,但也许你正在做某事。也许我初始化 TextController 有问题
              • 我建议使用 chrome 或 firefox 开发工具放置一个断点,以便您检查对象的外观。
              【解决方案11】:

              ' title' 中没有空格或有趣的字符,是吗?如果您在对象/地图定义中引用了标识符,则可以定义它们。例如:

              var problem = {
                  ' title': 'Foo',
                  'content': 'Bar'
              };
              

              这可能会导致 console.log(item) 显示类似于您的预期,但是当您访问 title 属性时没有前面的空格时会导致您的 undefined 问题。

              【讨论】:

              • doc 是 mongo db 查询的结果,所以我只是遍历这些对象。我确实尝试过 item['title'] 和 item['title']。没有运气
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-07-12
              • 2012-09-28
              • 1970-01-01
              • 1970-01-01
              • 2017-11-27
              相关资源
              最近更新 更多