无法访问来自 Mongoose 的 populate() 对象的属性?

Zan*_*aes 5 mongoose mongodb node.js

这很奇怪......我使用 populate() 和一个 ref 来填充我的架构中的数组,但随后无法访问这些属性。换句话说,模式是这样的:

new Model('User',{
    'name': String,
    'installations': [ {type: String, ref: 'Installations'} ],
    'count': Number,
}
Run Code Online (Sandbox Code Playgroud)

当然,Insallations 是另一种模式。

然后我找到并填充一组用户...

model.find({count: 0}).populate('installations').exec( function(e, d){
    for(var k in d)
    { 
        var user = d[k];
        for(var i in user.installations)
        {
            console.log(user.installations[i]);
        }
    }
} );
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好!我看到打印出不错的数据,如下所示:

{ runs: 49,
hardware: 'macbookpro10,1/x86_64',
mode: 'debug',
version: '0.1' }
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试实际访问这些属性中的任何一个,它们都是未定义的!例如,如果我添加另一个控制台日志:

console.log(user.installations[i].mode);
Run Code Online (Sandbox Code Playgroud)

然后我看到此日志打印了“未定义”。如果我尝试对对象进行操作,如下所示:

 Object.keys(user.installations[i]).forEach(function(key) { } );
Run Code Online (Sandbox Code Playgroud)

然后我得到一个典型的“[TypeError: Object.keys call on non-object]”错误,表明 user.installations[i] 不是一个对象(即使它像它一样输出到控制台)。所以,我什至尝试了一些丑陋的东西......

var install = JSON.parse(JSON.stringify(user.installations[i]));
console.log(install, install.mode);
Run Code Online (Sandbox Code Playgroud)

而且,第一个输出(安装)是一个很好的对象,包含属性 'mode'...但第二个输出未定义。

是什么赋予了?

Zan*_*aes 6

最后,我解决了这个问题...

我试着做一个 console.log(typeof user.installations[i]); 并得到“字符串”作为输出。这看起来很奇怪,因为直接打印对象会创建看起来像普通对象而不是字符串的控制台输出(上图)。所以,我试着做一个 JSON.parse(); 在对象上,但收到错误“SyntaxError: Unexpected token r”

终于,我明白是怎么回事了。我上面描述的“漂亮的控制台输出”是用 \n(换行符)格式化的字符串的结果。无论出于何种原因,我都没有预料到这一点。JSON.parse() 错误是由于 node.js 解析器在尝试解析不带引号的对象键时存在已知的必要性;在这里看到 SO 问题: 为什么 JSON.parse('{"key" : "value"}') 做得很好,但 JSON.parse('{key : "value"}') 没有?.

具体来说,请注意我的 JSON 解析器在字符 'r' 上失败,这是“runs”的第一个字符,它是我的 JSON 字符串(上图)中的第一个键。起初我担心我需要一个自定义的 JSON 解析器,但后来这个问题给我带来了麻烦。

回顾我的原始模式。我使用字符串类型来定义安装引用,因为数组字段将安装的 _id 属性存储为字符串。我假设 .populate() 字段在输出时将对象转换为字符串。

最后,我仔细查看了 Mongoose 文档,意识到我应该根据 Schema.ObjectID 引用对象。这解释了一切,但肯定让我在我的架构和其他地方的代码中做一些修复......