Mongoose/MongoDB 结果字段在 Javascript 中显示为未定义

Posted

技术标签:

【中文标题】Mongoose/MongoDB 结果字段在 Javascript 中显示为未定义【英文标题】:Mongoose/MongoDB result fields appear undefined in 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”访问有关,或者他们试图使对象超出函数的范围。在这种情况下,我不认为我在做任何一个,但如果我错了,请告诉我。谢谢

【问题讨论】:

【参考方案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']。没有运气

以上是关于Mongoose/MongoDB 结果字段在 Javascript 中显示为未定义的主要内容,如果未能解决你的问题,请参考以下文章

在 Mongoose/MongoDB 的文档中过滤数组、子文档、数组、文档

Mongoose/Mongodb Aggregate - 对多个字段进行分组和平均

如何使用 Autopopulate Mongoose Mongodb 选择要检索的字段?

无法使用函数(req,res,next,id)mongoose(mongodb)中的动态id字段进行查询

Paginate Mongoose / MongoDB查询:从一个点开始按两个字段排序[重复]

Mongoose MongoDB 找到数组字段中数组长度最小的那个