// backend\models\Playlist.js
const mongoose = require('mongoose');
const playlistSchema = new mongoose.Schema({
name: { type: String, required: true },
videos: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Video' }],
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
});
module.exports = mongoose.model('Playlist', playlistSchema);
// backend\models\Video.js
const mongoose = require('mongoose');
const commentSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
username: { type: String, required: true },
comment: { type: String, required: true },
date: { type: Date, default: Date.now },
});
const videoSchema = new mongoose.Schema({
title: String,
description: String,
url: String,
uploadDate: {
type: Date,
default: Date.now,
},
uploader: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
likes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
comments: [commentSchema],
cloudinary_id: { type: String, required: true },
});
module.exports = mongoose.model('Video', videoSchema);
// backend\models\User.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
userSchema.pre('save', async function (next) {
if (this.isModified('password')) {
this.password = await bcrypt.hash(this.password, 10);
}
next();
});
userSchema.methods.comparePassword = function (password) {
return bcrypt.compare(password, this.password);
};
module.exports = mongoose.model('User', userSchema);
The Playlist Modal has reference to Video Modal, The Video Modal has reference to User Modal, but I am receiving only the video id's present in Playlist Modal, not the entire video document.
This is how I am accessing using API:
router.get('/playlist/:id/videos', authMiddleware, async (req, res) => {
try {
const playlist = await Playlist.findById(req.params.id)
.populate({
path: 'videos',
populate: { path: 'uploader' }
});
if (playlist.userId.toString() !== req.userData.userId) {
return res.status(403).json({ message: 'Forbidden' });
}
res.json(playlist.videos);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
I tried noticing that I have implemented populate in other APIs & it works fine, but not here.
Please see the code below. The same three schema definitions have been used over here. And then created a test playlist. The retrieval code is also the same used in the original question. Please see the output, the video document now is populated.
Request please pay close attention to the code at the line “setting video reference”. This could be the potential line to be checked against your code. As you know, this line sets the reference with the Video document, the link between the playlist document and the video document. Since the schema definitions and the find statement are found working fine as it is, this line would be the most potential one to review.
If it turns out that the above mentioned line is also correct in your code, please repeat the test with a new set of documents - create a new user, a new video document against the new user, and a new playlist against the new video.
// MongoDB: 7.0.2
// Mongoose : 8.3.2
// Node.js v21.6.0.
// populateissue.mjs
import mongoose, { Schema } from 'mongoose';
main().catch((err) => {
console.log(err);
});
async function main() {
await mongoose.connect('mongodb://127.0.0.1:27017/myapp');
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
const Usermodel = mongoose.model('User', userSchema);
await Usermodel.deleteMany();
const commentSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
username: { type: String, required: true },
comment: { type: String, required: true },
date: { type: Date, default: Date.now },
});
const videoSchema = new mongoose.Schema({
title: String,
description: String,
url: String,
uploadDate: {
type: Date,
default: Date.now,
},
uploader: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
likes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
comments: [commentSchema],
cloudinary_id: { type: String, required: true },
});
const Videomodel = mongoose.model('Video', videoSchema);
await Videomodel.deleteMany();
const playlistSchema = new mongoose.Schema({
name: { type: String, required: true },
videos: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Video' }],
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
});
const Playlistmodel = mongoose.model('Playlist', playlistSchema);
await Playlistmodel.deleteMany();
const userdoc = new Usermodel({
username: 'somename',
password: 'somepassword',
});
const videodoc = new Videomodel({
title: 'someTitle',
uploader: userdoc._id,
cloudinary_id: 'someId',
});
const playlistdoc = new Playlistmodel({
name: 'someName',
videos: videodoc._id, // setting video reference
userId: userdoc._id, // kept it the same as uploader since it is a test data
});
await userdoc.save();
await videodoc.save();
await playlistdoc.save();
const playlistdocs = await Playlistmodel.findById(playlistdoc._id).populate({
path: 'videos',
populate: { path: 'uploader' },
});
console.log(playlistdocs);
console.log(playlistdocs.videos);
}
// output
{
_id: new ObjectId('6629c3f3450ae04736c1877e'),
name: 'someName',
videos: [
{
_id: new ObjectId('6629c3f3450ae04736c1877d'),
title: 'someTitle',
uploader: [Object],
likes: [],
cloudinary_id: 'someId',
uploadDate: 2024-04-25T02:46:11.929Z,
comments: [],
__v: 0
}
],
userId: new ObjectId('6629c3f3450ae04736c1877c'),
__v: 0
}
[
{
_id: new ObjectId('6629c3f3450ae04736c1877d'),
title: 'someTitle',
uploader: {
_id: new ObjectId('6629c3f3450ae04736c1877c'),
username: 'somename',
password: 'somepassword',
__v: 0
},
likes: [],
cloudinary_id: 'someId',
uploadDate: 2024-04-25T02:46:11.929Z,
comments: [],
__v: 0
}
]