skip to Main Content

I’m very new to Nodejs and MongoDB, I have 3 collections one for chapter,one for lecture and one for asset
every course have chapters, every chapter has array of lectures and every lecture have assets
so I want to get chapters by courseId which already done, and inside chapter to get its lectures and in every lecture to get its assets

Course:

const mongoose = require('mongoose');
var Double = require('@mongoosejs/double');

const courseSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true,
    },
    requirements: {
        type: String,
    },
    
    code: {
        type: String,
        required: true,
    },
    coverPhoto: {
        type: String,
        required: false,
    },
    
    description: {
        type: String
    },

    instructor:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'User',
        required:true
    },

    category:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'Category',
        required:true
    },

    learns: [{
        type: String
    }],
    subCategory:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'SubCategory',
        required:true
    },


    isCoaching: {
        type: Boolean,
        default: false,
    },

    isFree: {
        type: Boolean,
        default: false,
    },

    price: {
        type: Double,
        default: 0,
    },
    rating: {
        type: Double,
        default: 0,
    },
    isPublished: {
        type: Boolean,
        default: false,
    },

    dateCreated: {
        type:Date,
        default:Date.now,
    },
});

exports.Course = mongoose.model('Course', courseSchema);
exports.courseSchema = courseSchema;

Chapter:

    const mongoose = require('mongoose');

    const chapterSchema = new mongoose.Schema({
        course:{
            type:mongoose.Schema.Types.ObjectId,
            ref:'Course',
            required:true
        },
        title: {
            type: String,
            required: true,
        },
        sort_order: {
            type: Number,
            default: 1,
        },
        is_published: {
            type: Boolean,
            default: true,
        },

    });
    exports.Chapter = mongoose.model('Chapter', chapterSchema);
    exports.chapterSchema = chapterSchema;

Lecture:

const mongoose = require('mongoose');

const lectureSchema = new mongoose.Schema({
    chapter:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'Chapter',
        required:true
    },

    title: {
        type: String,
        required: true,
    },
    sort_order: {
        type: Number,
        default: 1,
    },

    is_published: {
        type: Boolean,
        default: true,
    },


});

exports.Lecture = mongoose.model('Lecture', lectureSchema);
exports.lectureSchema = lectureSchema;

Asset:

const mongoose = require('mongoose');

const assetSchema = new mongoose.Schema({
    lecture:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'Lecture',
        required:true
    },
    title: {
        type: String,
        required:true
    },
    asset_type: {
        type: String
    },
    description: {
        type: String,
        require:true
    },

    file_url: {
        type: String,
        require:true
    },
    page_number: {
        type: Number,
        default:1
    },
    time_estimation: {
        type: String,
        require:true
    },

    is_external: {
        type: Boolean,
        default: false,
    },

    is_published: {
        type: Boolean,
        default: true,
    },


});


exports.Asset = mongoose.model('Asset', assetSchema);
exports.assetSchema = assetSchema;

Get Chapters of a course

router.get(`/`, async (req, res) => {
    let course_filter = {};
    if (req.query.course) {
        course_filter = {course:req.query.course};
    }
    const chapterList = await Chapter.find(course_filter).populate('lecture').sort('sort_order');
    if (!chapterList) {
        res.status(500).json({ success: false });
    }
    res.send(chapterList);
});

2

Answers


  1. You have to nest the populate in another populate:

    router.get(`/`, async (req, res) => {
      let course_filter = {};
      if (req.query.course) {
        course_filter = { course: req.query.course };
      }
      const chapterList = await Chapter.find(course_filter)
        .populate({ path: 'lectures', populate: { path: 'assets' } })
        .sort('sort_order');
      if (!chapterList) {
        res.status(500).json({ success: false });
      }
      res.send(chapterList);
    });
    

    You have to ensure that you have set a virtual for ‘assets’ prop in lectureSchema accordingly. I assume you have also done it for your ‘Chapter’ schema.

    If not, you have do add the following:

    virtual for Chapter schema:

    chapterSchema.virtual('lectures', {
      ref: Lecture.collection.collectionName,
      localField: '_id',
      foreignField: 'chapter'
    });
    

    virtual for Lecture schema:

    lectureSchema.virtual('assets', {
      ref: Asset.collection.collectionName,
      localField: '_id',
      foreignField: 'lecture'
    });
    
    Login or Signup to reply.
  2. using simple aggregation:

    const chapterList = await Chapter.aggregate([{
        $lookup: {
        from: 'lectures',
        localField: '_id',
        foreignField: 'chapter',
        as: 'lectures'
        }}]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search