Mongoose - 使用 .populate 访问嵌套对象

Posted

技术标签:

【中文标题】Mongoose - 使用 .populate 访问嵌套对象【英文标题】:Mongoose - accessing nested object with .populate 【发布时间】:2014-08-15 16:01:44 【问题描述】:

架构定义

团队.js

var TeamSchema = new Schema(
    // Team Name.
    name: String,
    lead: String,
    students :type: [
      block : Number,
      status : String,
      student : 
        type: Schema.ObjectId,
        ref: 'Student'
    ]
);

Student.js

var StudentSchema = new Schema(
   name: String,
   rollNo : Number,
   class : Number
);

我如何填充“学生”以获得输出,如下所示:

团队


    "__v": 1,
    "_id": "5252875356f64d6d28000001",
    "students": [
        
            "__v": 1,
            "_id": "5252875a56f64d6d28000002",
             block : 1,
             status : joined,
            "student": 
                "name": Sumeeth
                "rollNo" : 2
                "class" : 5
            
        ,
        
            "__v": 1,
            "_id": "5252875a56f64d6d28000003",
            block : 1,
            status : joined,
            "student": 
                "name": Sabari
                "rollNo" : 3
                "class" : 4
            
        
    ],
    "lead": "Ratha",   

这是我使用 Mongoose 获取文档的 JS:

Team.findOne(
    _id: req.team._id
)            
.populate('students')
.select('students')
.exec(function(err, team) 
    console.log(team);
    var options = 
        path: 'students.student',
        model: 'Student'
    ;
    Student.populate(team.students,options,function(err, students) 
        console.log(students);
        if (err) 
            console.log(students);
            res.send(500, 
                message: 'Unable to query the team!'
            );
         else 
            res.send(200, students);
        
    );
);

在我的控制台输出中,我得到以下信息:

 _id: 53aa434858f760900b3f2246,
  students
   [  block : 1
       status: 'joined'
       _id: 53aa436b58f760900b3f2249 ,
      block : 1
       status: 'joined'
       _id: 53aa436b58f760900b3f2250 ]

预期的输出是:

   _id: 53aa434858f760900b3f2246,
      students
       [  block : 1
           status: 'joined'
           student :
              "name": Sumeeth
              "rollNo" : 2
              "class" : 5
            
         ,
          block : 1
           status: 'joined'
           student :
               "name": Sabari
              "rollNo" : 3
              "class" : 4
            
        
     ]
    

请有人帮我解决我的错误。我应该如何使用 .populate,这样,我才能获得整个学生对象,而不仅仅是它的 id。

参考: Populate nested array in mongoose

【问题讨论】:

也许在您的问题中显示您的架构定义。 【参考方案1】:

这是您想要的简化版本。

要设置的基本资料,首先是“学生”:

 
   "_id" : ObjectId("53aa90c83ad07196636e175f"), 
   "name" : "Bill",
   "rollNo" : 1,
   "class" : 12 
,
 
    "_id" : ObjectId("53aa90e93ad07196636e1761"),
    "name" : "Ted",
    "rollNo" : 2,
    "class" : 12

然后是“团队”集合:

 
    "_id" : ObjectId("53aa91b63ad07196636e1762"),
    "name" : "team1",
    "lead" : "me",
    "students" : [ 
         
            "block" : 1,
            "status" : "Y",
            "student" : ObjectId("53aa90c83ad07196636e175f")
        ,
         
            "block" : 2,
            "status" : "N",
            "student" : ObjectId("53aa90e93ad07196636e1761")
        
    ]

这就是你的做法:

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

mongoose.connect('mongodb://localhost/team');

var teamSchema = new Schema(
  name: String,
  lead: String,
  students: [
    block: Number,
    status: String,
    student: 
      type: Schema.ObjectId, ref: 'Student'
    
  ]
);

var studentSchema = new Schema(
  name: String,
  rollNo: Number,
  class: Number
);

var Team = mongoose.model( "Team", teamSchema );
var Student = mongoose.model( "Student", studentSchema );

Team.findById("53aa91b63ad07196636e1762")
  .select('students')
  .exec(function(err, team) 
    console.log( team );

    async.forEach(team.students, function(student,callback) 
      Student.populate(
        student,
         "path": "student" ,
        function(err,output) 
          if (err) throw err;
          callback();
        
      );
    ,function(err) 
      console.log( JSON.stringify( team, undefined, 4 ) );
    );

  );

它会给你结果:


    "_id": "53aa91b63ad07196636e1762",
    "students": [
        
            "block": 1,
            "status": "Y",
            "student": 
                "_id": "53aa90c83ad07196636e175f",
                "name": "Bill",
                "rollNo": 1,
                "class": 12
            
        ,
        
            "block": 2,
            "status": "N",
            "student": 
                "_id": "53aa90e93ad07196636e1761",
                "name": "Ted",
                "rollNo": 2,
                "class": 12
            
        
    ]

您确实不需要“异步”模块,但我只是“习惯”。它不会“阻塞”,因此我认为它更好。

如您所见,您最初的 .populate() 调用没有做任何事情,因为它期望从数组输入中“键”关闭外部集合中的 _id 值,而这个“严格来说”并非如此因为“key”在包含“外键”的“student”上。

我确实在recent answer here 中提到了这一点,可能并不完全针对您的情况。您的搜索似乎没有找到正确的“相同答案”(尽管不完全正确)供您参考。

【讨论】:

【参考方案2】:

我也遇到过同样的问题。我已使用此代码进行救援:

Team.findOne(_id: req.team._id)
.populate( path: "students.student")
.exec(function(err, team) 
       console.log(team);
);

【讨论】:

【参考方案3】:

你想多了。让 Mongoose 为您完成工作。

Team.findOne(
    _id: req.team._id
)            
.populate(path:'students')
.exec(function(err, team) 
    console.log(team);
);

这会将学生作为文档返回,而不仅仅是 ID。

【讨论】:

【参考方案4】:

TL DR

const team = await Team.findById(req.team._id)
  .populate("students");

team.students = await Student.populate(team.students, path: "student");

上下文

阅读所有答案后,我测试了所有内容,只有 Neil Lun's answer 为我工作。问题是它正在通往cb地狱的道路上。所以我有点头疼,然后“重构”成一个优雅的单线。

const foundPost = await Post.findById(req.params.id)
  .populate("comments")
  .populate("author");

foundPost.comments = await User.populate(foundPost.comments, path: "author"); 

我最初的问题:


  title: "Hello World",
  description: "lorem",
  author: /* populated */,
  comments: [ // populated
    text: "hi", author: /* not populated */ 
  ]
;

我的模型基本上是这样的:

User = 
  author,
  password
;

Post = 
  title,
  description,
  author: , //ref User
  comments: [] // ref Comment
;

Comment = 
  text,
  author:  // ref User
;

问题解决后的输出:


  comments: [
    
      _id: "5dfe3dada7f3570b60dd977f",
      text: "hi",
      author: _id: "5df2f84d4d9fcb228cd1df42", username: "jo", password: "123"
    
  ],
  _id: "5da3cfff50cf094c68aa2a37",
  title: "Hello World",
  description: "lorem",
  author: 
    _id: "5df2f84d4d9fcb228cd1aef6",
    username: "la",
    password: "abc"
  
;

【讨论】:

以上是关于Mongoose - 使用 .populate 访问嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose中关联查询populate的使用

Mongoose 动态模型,不能使用 populate()

无法从 Mongoose 访问 populate()'d 对象的属性?

mongoose#populate 在数组内的嵌套对象中返回 null

Mongoose 在使用 $facet 进行聚合时如何使用 populate()?

mongoose.populate() 未显示填充内容