fix(submissions): resolve Mongoose populate error for hybrid BlogPost model

- BlogPost uses native MongoDB (not Mongoose), causing MissingSchemaError
- Removed all .populate('blogPostId') calls that tried to reference non-existent Mongoose model
- Manually fetch blog post data in controllers when needed
- Updated getSubmissions, getSubmissionById, getSubmissionByBlogPost, exportSubmission
- Updated SubmissionTracking static methods: getByStatus, getByPublication
- Standalone submissions (like Le Monde) now display without errors
This commit is contained in:
TheFlow 2025-10-24 10:19:33 +13:00
parent 7f865fbe70
commit 6626cbc7e1
2 changed files with 81 additions and 15 deletions

View file

@ -81,24 +81,44 @@ async function getSubmissions(req, res) {
if (status) query.status = status;
if (publicationId) query.publicationId = publicationId;
// NOTE: BlogPost is a native MongoDB class, not a Mongoose model,
// so we can't use .populate() for blogPostId. Fetch blog post data separately if needed.
const submissions = await SubmissionTracking.find(query)
.populate({
path: 'blogPostId',
select: 'title slug',
options: { strictPopulate: false } // Allow null blogPostId
})
.populate('createdBy', 'email')
.sort({ submittedAt: -1, createdAt: -1 })
.limit(parseInt(limit, 10))
.skip(parseInt(offset, 10));
// Manually fetch blog post titles for submissions that have blogPostId
const submissionsWithBlogData = await Promise.all(
submissions.map(async (submission) => {
const submissionObj = submission.toObject();
if (submissionObj.blogPostId) {
try {
const blogPost = await BlogPost.findById(submissionObj.blogPostId);
if (blogPost) {
submissionObj.blogPost = {
title: blogPost.title,
slug: blogPost.slug
};
}
} catch (err) {
console.error(`[Submissions] Error fetching blog post ${submissionObj.blogPostId}:`, err.message);
}
}
return submissionObj;
})
);
const total = await SubmissionTracking.countDocuments(query);
res.json({
success: true,
count: submissions.length,
count: submissionsWithBlogData.length,
total,
data: submissions
data: submissionsWithBlogData
});
} catch (error) {
console.error('[Submissions] Get submissions error:', error);
@ -118,7 +138,6 @@ async function getSubmissionById(req, res) {
const { id } = req.params;
const submission = await SubmissionTracking.findById(id)
.populate('blogPostId', 'title slug content')
.populate('createdBy', 'email')
.populate('lastUpdatedBy', 'email')
.populate('notes.author', 'email');
@ -130,9 +149,27 @@ async function getSubmissionById(req, res) {
});
}
const submissionObj = submission.toObject();
// Manually fetch blog post data if blogPostId exists
if (submissionObj.blogPostId) {
try {
const blogPost = await BlogPost.findById(submissionObj.blogPostId);
if (blogPost) {
submissionObj.blogPost = {
title: blogPost.title,
slug: blogPost.slug,
content: blogPost.content
};
}
} catch (err) {
console.error(`[Submissions] Error fetching blog post:`, err.message);
}
}
res.json({
success: true,
data: submission
data: submissionObj
});
} catch (error) {
console.error('[Submissions] Get submission by ID error:', error);
@ -282,7 +319,6 @@ async function getSubmissionByBlogPost(req, res) {
const { blogPostId } = req.params;
const submission = await SubmissionTracking.findOne({ blogPostId })
.populate('blogPostId', 'title slug content')
.populate('createdBy', 'email')
.populate('lastUpdatedBy', 'email');
@ -293,9 +329,25 @@ async function getSubmissionByBlogPost(req, res) {
});
}
const submissionObj = submission.toObject();
// Manually fetch blog post data
try {
const blogPost = await BlogPost.findById(blogPostId);
if (blogPost) {
submissionObj.blogPost = {
title: blogPost.title,
slug: blogPost.slug,
content: blogPost.content
};
}
} catch (err) {
console.error(`[Submissions] Error fetching blog post:`, err.message);
}
res.json({
success: true,
data: submission
data: submissionObj
});
} catch (error) {
console.error('[Submissions] Get by blog post error:', error);
@ -370,8 +422,7 @@ async function exportSubmission(req, res) {
const { id } = req.params;
const { format = 'json' } = req.query;
const submission = await SubmissionTracking.findById(id)
.populate('blogPostId', 'title content');
const submission = await SubmissionTracking.findById(id);
if (!submission) {
return res.status(404).json({
@ -383,6 +434,21 @@ async function exportSubmission(req, res) {
const language = req.query.language || 'en';
const packageData = submission.exportPackage(language);
// Add blog post data if blogPostId exists
if (submission.blogPostId) {
try {
const blogPost = await BlogPost.findById(submission.blogPostId);
if (blogPost) {
packageData.blogPost = {
title: blogPost.title,
content: blogPost.content
};
}
} catch (err) {
console.error(`[Submissions] Error fetching blog post:`, err.message);
}
}
if (format === 'json') {
res.json({
success: true,

View file

@ -218,20 +218,20 @@ SubmissionTrackingSchema.virtual('submissionDurationDays').get(function() {
/**
* Get submissions by status
* NOTE: BlogPost is a native MongoDB class, not Mongoose model, so we can't populate it
*/
SubmissionTrackingSchema.statics.getByStatus = async function(status) {
return await this.find({ status })
.populate('blogPostId', 'title slug')
.populate('createdBy', 'email')
.sort({ submittedAt: -1 });
};
/**
* Get submissions for a specific publication
* NOTE: BlogPost is a native MongoDB class, not Mongoose model, so we can't populate it
*/
SubmissionTrackingSchema.statics.getByPublication = async function(publicationId) {
return await this.find({ publicationId })
.populate('blogPostId', 'title slug')
.sort({ submittedAt: -1 });
};