7

Schema Definitions

Team.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
});

How I can populate "student" to get output, as below:

team

{
    "__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",   
}

This is JS I use to get the document using Mongoose:

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);
        }
    });
});

In my console output I get the following:

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

And the expected output is:

  { _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
           } 
        }
     ]
    }

Some one please help me where I am wrong. How should I make use of .populate, so that , I can get the entire student object and not only its id.

Reference : Populate nested array in mongoose

1
  • 1
    Perhaps show your Schema definitions in your question. Commented Jun 25, 2014 at 8:01

4 Answers 4

4

I have been facing same issue. I have use this code for my rescue :

Team.findOne({_id: req.team._id})
.populate({ path: "students.student"})
.exec(function(err, team) {
       console.log(team);
});
Sign up to request clarification or add additional context in comments.

Comments

3

Here is a simplified version of what you want.

Basic data to set up, first the "students":

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

And then the "teams" collection:

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

This is how you do it:

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 ) );
    });

  });

And it gives you the results:

{
    "_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
            }
        }
    ]
}

You really do not need the "async" module, but I am just "in the habit" as it were. It doesn't "block" so therefore I consider it better.

So as you can see, you initial .populate() call does not do anything as it expects to "key" off of an _id value in the foreign collection from an array input which this "strictly speaking" is not so as the "key" is on "student" containing the "foreign key".

I really did cover this in a recent answer here, maybe not exactly specific to your situation. It seems that your search did not turn up the correct "same answer" ( though not exactly ) for you to draw reference from.

Comments

1

You are overthinking it. Let Mongoose do the work for you.

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

This will return students as documents rather than just the ids.

Comments

1

TL DR

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

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

Context

Reading from all the answers I went testing everything and just Neil Lun's answer worked for me. The problem is it was on the path to a cb hell. So I cracked my head a little and 'refactored' to an elegant one-liner.

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

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

My initial problem:

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

How my models basically are:

User = {
  author,
  password
};

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

Comment = {
  text,
  author: {} // ref User
};

The output after problem solved:

{
  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"
  }
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.