Mongoose Populate 返回 null 或 undefined

Posted

技术标签:

【中文标题】Mongoose Populate 返回 null 或 undefined【英文标题】:Mongoose Populate returning null or undefined 【发布时间】:2013-11-23 21:01:41 【问题描述】:

很抱歉,如果这是一个 n00b 问题,我已经搜索 Google 和 Stack 几个小时了,我必须问一下!

我有两个模式,用户和故事,如下所示。我正在尝试使用 Ref 选项为 Story 引用 User 以在查询中填充 - 我之前使用过 mysql,因此想尝试复制 JOIN 语句。 每当我尝试使用填充时,我只会返回 objectID 或 null(如下所示)。

于 11 月 12 日编辑以修复硬编码 ID 并添加控制台数据

story-schema.js

var mongoose = require('mongoose'),
Schema = mongoose.Schema,
User = require('./user-schema');

var StorySchema = new Schema(  
title:  type: String, required: true ,  
author_id:  type: Schema.Types.ObjectId, ref: 'User' ,
summary:  type: String, required: true ,
rating:  type: String, required: true 
);

module.exports = mongoose.model('Story', StorySchema, 'stories');

user-schema.js

var mongoose = require('mongoose'),
Schema = mongoose.Schema;

var UserSchema = new Schema(
    username:  type: String, required: true, index:  unique: true  ,
    is_admin: type: Boolean, required: true, default: false 
);

保存 - 例如 id 硬编码

app.post('/api/new_story', function(req, res)
var story;
story = new Story(
    title: req.body.title,
    author_id: mongoose.Types.ObjectId(req.params._id), 
            /* ex of req.params._id: 527fc8ff241cdb8c09000003*/
    summary: req.body.summary,
    rating: req.body.rating
);

story.save(function(err) 
    if (!err) 
        return console.log("created");
     else 
        return console.log(err);
    
);
return res.send(story);
);

登录终端时的示例用户


"__v" : 0,
"_id" : ObjectId("527fc8ff241cdb8c09000003"),
"is_admin" : false,
"username" : "ted"

登录终端时的示例故事


"title" : "Test Story",
"author_id" : "527fc8ff241cdb8c09000003",
"summary" : "Test summary",
"rating" : "12",
"_id" : ObjectId("52827692496c16070b000002"),
"__v" : 0

查询

//other mongoose/app includes above
User = require('./config/schema/user-model'),
Story = require('./config/schema/story-model');

// data.author_id = 527fc8ff241cdb8c09000003 
// data.author_id.username = undefined
app.get('/api/query/:id', function (req, res)
return Story.findOne(_id:req.params.id)
.populate(  path: 'User'  )
.exec(function (err, data) 
            console.log(data.author_id);
            console.log(data.author_id.username);
          if (err) 
            return res.json(error:err)
          
        )
);

// data.author_id = null 
app.get('/api/query2/:id', function (req, res)
return Story.findOne(_id:req.params.id) //_id hardcoded for example
.populate( 'author_id' )
.exec(function (err, data) 
            console.log(data.author_id);
          if (err) 
            return res.json(error:err)
          
        )
);

在第一个查询中,我得到了我已经保存回来的 author_id,这很有意义,因为这是我保存的 - 但我访问了用户名。

在第二个查询中,我什至无法访问我已经保存的 author_id。

编辑:我可以在没有“填充”的情况下正常运行正常的 GET 查询

我希望发生的事情

是为了能够从故事中获取作者信息——这更像是一个概念证明。 最终我想在 User 模型中引用 Story _id,因为一个用户可以有很多故事,但每个故事只有一个用户,但我想我会先从这里开始。

【问题讨论】:

【参考方案1】:

由于您的示例包含原始对象 ID,甚至没有引用为有效的 javascript 字符串,因此很难理解您的问题中的错误与代码中的错误,但大多数情况下,您的第二个查询看起来应该可以工作。我怀疑你混淆了你的 ObjectId 值。您正在为您的故事和您的用户使用相同的 ObjectId,但这是行不通的:

   author_id: mongoose.Types.ObjectId(528149b38da5b85003000002),

这与您用于查找故事的 ID 相同。所以我认为解决方法是:

    确保您在用户集合中有有效的用户记录 确保您的测试故事记录的 story.author_id 与之匹配 确保您是通过故事 ID 而非作者 ID 查找故事。

如果您仍然无法使其正常工作,请将整个内容编码到一个 .js 文件中,其中包含两种模式、两种模型以及一些用于创建记录的代码,然后执行查询并发布。

【讨论】:

您好,我已经更新了示例以不包含硬编码数据 - 这是我努力使事情更清晰(失败)的复制和粘贴错误。尝试仅返回用户 (1) 时,我可以返回有效的用户记录。 author_id 与用户的 _id 匹配,但是即使我尝试将其保存为 ObjectID,它也会在控制台中显示为字符串。会是这样吗? 好的,所以是的,我认为 story.author_id 是 String 而不是 ObjectId 的事实是一个问题。这是一个数据问题,您只需加载并重新保存该记录即可解决。我的猜测是,您在 mongoose 架构完成之前或通过 mongo shell 或其他方式创建了该故事,但本质上数据不符合架构,这始终是此类数据库的风险。 好的,我创建了一个新记录但仍然没有运气,然后我尝试了一个新的 Schema,新的集合以防万一但没有快乐。之后,我将所有内容都放在一个文件中,就像您的第一条评论一样,它与原始 /api/query2/:id 等一起工作(!) - 我认为这一定与彼此需要的单独文件有关 - 我找到了这个答案@ 987654321@ 但这在拆分它们时也对我不起作用。所以现在,1个文件! 啊,是的,您可能创建了一个循环需求图,这是节点中的一个禁忌。不要使用require 来相互引用每个模型,只需在架构引用中使用字符串模型名称即可。 就是这样!非常感谢!【参考方案2】:

我被这个问题困扰了一周。在尝试了一切并确保我没有循环引用之后,我决定重置我的数据库。

删除所有集合并再次存储它们后,我由猫鼬的populate() 管理的所有关系都正常工作。

这太令人沮丧了,因为这个问题没有记录在案,而且我浪费了 20 到 30 个小时试图让一个愚蠢的集合参考工作。

【讨论】:

我们现在面临着类似的问题。我们没有对 mongoose 的版本进行任何更改,对于过去 4 年运行良好的一些 populate() 案例仍然返回 null 这里我使用Model.populate() 方法....【参考方案3】:

您是否可能忘记在架构中包含“ref”字段? 我刚刚遇到了这个问题,在我的 Schema 中添加了一个 ref 字段后,它可以立即工作,无需重置数据库。希望这些信息对您有所帮助。

我在这里找到了一个示例:https://mongoosejs.com/docs/3.0.x/docs/populate.html。虽然它是 3.0.x 版的文档,但我发现它甚至对我现在使用的 5.5.5 版也很有帮助。

【讨论】:

经过数小时的调试和挖掘可笑的可怕 Mongoose 文档后,这个答案终于暗示了对 refs 的需求。谢谢狮子座。 FML。【参考方案4】:

我偶然发现了这一点,问题在于引用了已删除的文档。如果可以,请重置您的数据库或仔细检查引用的 id

【讨论】:

【参考方案5】:

当将 ref 声明为模型类引用而不是带有模型名称的字符串时,我设法解决了这个问题。

// before
let Schema = mongoose.Schema(
    name: String,
    author:  type: Schema.Types.ObjectId, ref: 'Author' 
);

//after
let Schema = mongoose.Schema(
    name: String,
    author:  type: Schema.Types.ObjectId, ref: Author 
);

【讨论】:

你应该包含/要求你想要引用的类,这只是一个例子。不要只是对答案投反对票,并尝试分析示例。【参考方案6】:

如果您的数据非常小,请尝试从与填充和主表相关的表中清除您的数据

【讨论】:

【参考方案7】:

我在这个问题上停留了 5-6 个小时,并找到了一个非常简单的解决方案。在这种情况下,您可以在此处查看:

    
   "title" : "Test Story",
   "author_id" : "527fc8ff241cdb8c09000003",
   "summary" : "Test summary",
   "rating" : "12",
   "_id" : ObjectId("52827692496c16070b000002"),
   "__v" : 0
   

在 author_id 值 '527fc8ff241cdb8c09000003' 中基本上是一个“字符串”而不是 ObjectId。当您从 json 或 csv 恢复数据库并且在此过程中 ObjectId 转换为字符串时,会发生这种情况。在我的情况下,我使用 Python 转储数据并尝试使用 express 检索数据。 因此,为了解决这个问题,我简单地使用 express 更新了数据,现在“填充”正在工作 尝试更新数据:

 const  ObjectId   = require('bson');
    app.get('/update-data', (req,res)=>
         Story.find()
        .exec((err,posts)=>
            for(let value of posts)
            
             User.findOne( _id : value.author_id )
             exec((err,userData)=>
                      Story.update( _id : value._id ,   author_id : ObjectId(userData._id) )
              .exec((error, resData)=>
                   console.log(resData);
                 );
               )
            
            
            res.send('Data Updated, try populating data again');
        );
    );
    

就是这样,在重新建立与用户的关系后,再次尝试填充该字段。

更新 1: 我忘了提到'ObjectId()'所需的包 必须包括这个

const  ObjectId   = require('bson');

更新 2: 在深入挖掘之后,我发现更新不是解决方案。我发现您需要包含要填充的所有模型。 例如:有一个连接到用户的 countryModel。然后在您的代码国家模型和用户模型中都应该像这样包含:

var userModel = require('../<path to model>/userModel');
var countryModel = require('../<path to model>/countryModel');

但是您没有使用 countryModel,但需要启动它。对于国家/地区型号代码应为: countryModel.js

const mongoose = require('mongoose');

const countrySchema = mongoose.Schema(
country_name : String,
flag_image : String,
country_code : String
);

//user model 
var countryModel = mongoose.model('countries', countrySchema);
module.exports = countryModel;

【讨论】:

【参考方案8】:

首先,当您在创建一些集合后添加填充方法时会发生这种情况。

您可以为连接的模型(全部)提出新请求并创建新集合。那么 populate 方法应该可以工作了。

以前创建的模型仍会发送 null,但新创建的集合应返回填充数据。

【讨论】:

【参考方案9】:

当您尝试填充数据库中不再存在的内容时,有时会发生此错误。由于这个原因,我遇到了这个错误。

【讨论】:

以上是关于Mongoose Populate 返回 null 或 undefined的主要内容,如果未能解决你的问题,请参考以下文章

Model.populate() 不是 Mongoose 中的返回文档

Mongoose Populate 返回空数组

Mongoose Populate 返回空数组

Mongoose .populate 随机

19-3-18 mongoose 连表查询populate用法

Mongoose populate() 返回空数组