【问题标题】:Mongoose Populate returning null or undefinedMongoose Populate 返回 null 或 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,因为一个用户可以有很多故事,但每个故事只有一个用户,但我想我会先从这里开始。

【问题讨论】:

    标签: node.js mongodb mongoose populate


    【解决方案1】:

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

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

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

    1. 确保您在用户集合中有有效的用户记录
    2. 确保您的测试故事记录的 story.author_id 与之匹配
    3. 确保您是通过故事 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】:

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

            【讨论】:

              猜你喜欢
              • 2016-01-01
              • 2013-08-13
              • 1970-01-01
              • 2013-12-17
              • 2015-08-16
              • 2020-08-24
              • 1970-01-01
              • 2017-11-17
              相关资源
              最近更新 更多