问题描述
我正在为我的网站构建评论系统。我已经为这篇文章创建了这个架构,它的评论是:
let articleSchema = mongoose.Schema({
language: {
type: String,default: "english"
},slug: {
type: String,required: true
},image: {
type: String,title: {
type: String,tags: {
type: [String],author: {
type: mongoose.Schema.Types.ObjectId,ref: "User",date: {
type: Date,default: Date.Now()
},description: {
type: String,required: false
},body: {
type: String,translation: [
{
language: {
type: String,required: true
},title: {
type: String,tags: {
type: [String],description: {
type: String,required: false
},body: {
type: String,required: true
}
}
],comments: [{
author: {
type: mongoose.Schema.Types.ObjectId,ref: "User"
},date: {
type: Date,default: Date.Now()
},body: {
type: String,required: true
}
}]
});
现在我想做的是填充每个评论作者字段。
{
"comments": [
{
"author": "5f71d3b575f9f800943903af","date": "some date here","body": "comment body"
}
]
}
现在我填充完所有这些后想要得到的是:
{
"comments": [
{
"author": {
"username": "Username","avatar": "fox"
},"body": "comment body"
}
]
}
我该怎么做?
这是我当前的代码:
router.get('/article/:id',async (req,res) => {
const { id: articleId } = req.params;
const lang = req.i18n.language;
const langName = new Intl.displayNames(['en'],{ type: "language" }).of(lang).toLowerCase();
try {
console.log(langName);
if (req.i18n.language === "en") {
var article = await Article.findById(articleId)
.populate([
{path:'comments.author',select:'+photo +username'},{path:'author',select:'+photo +username'}
])
.select("title image tags author date description body comments");
} else {
var article = await Article
.aggregate([
{
$match: {
"_id": ObjectId(articleId)
}
},{
$unwind: "$translation"
},{
$match: {
"translation.language": langName
}
},{
$group: {
_id: "$_id",image: { $first: "$image" },title: { $first: "$translation.title" },tags: { $first: "$translation.tags" },author: { $first: "$author" },date: { $first: "$date" },description: { $first: "$translation.description" },body: { $first: "$translation.body" },comments: { $first: "$comments" }
}
},{
$lookup: {
from: "users",localField: "author",foreignField: "_id",as: "author"
}
},{
$unwind: {
path: "$author"
}
},{ ///////////////////// Here I need to populate the comment author. How can I do it?
$lookup: {
from: "users",localField: "comments.author",as: "comments.author"
}
},{
$unwind: {
path: "$comments.author"
}
},{
$project: {
image: 1,title: 1,tags: 1,date: 1,description: 1,body: 1,// comments: 1,"comments.date": 1,"comments.body": 1,"comments.author.username": 1,"comments.author.avatar": 1,"author.username": 1,"author.avatar": 1
}
}
],function(err,result) {
console.log(err)
return result;
});
console.log(article[0].comments[0]);
console.log(article);
}
if (!article) throw new Error();
} catch {
return res.status(404).render('errors/404');
}
res.render('articles/article',{
article: article[0]
});
});
解决方法
所以经过一些挖掘,我想出了这个解决方案:
router.get('/article/:id',async (req,res) => {
const { id: articleId } = req.params;
const lang = req.i18n.language;
const langName = new Intl.DisplayNames(['en'],{ type: "language" }).of(lang).toLowerCase();
try {
if (req.i18n.language === "en") {
var article = await Article.findById(articleId)
.populate([
{path:'comments.author',select:'+photo +username'},{path:'author',select:'+photo +username'}
])
.select("title image tags author date description body comments");
} else {
var article = await Article
.aggregate([
{
$match: {
"_id": ObjectId(articleId)
}
},{
$unwind: "$translation"
},{
$match: {
"translation.language": langName
}
},{
$lookup: {
from: "users",localField: "author",foreignField: "_id",as: "author"
}
},{
$unwind: {
path: "$author"
}
},{
$unwind: {
path: "$comments"
}
},localField: "comments.author",as: "comments.author"
}
},{
$group: {
_id: "$_id",root: { $mergeObjects: '$$ROOT' },image: { $first: "$image" },title: { $first: "$translation.title" },tags: { $first: "$translation.tags" },author: { $first: "$author" },date: { $first: "$date" },description: { $first: "$translation.description" },body: { $first: "$translation.body" },comments: { $push: "$comments" }
}
},{
$project: {
image: 1,title: 1,tags: 1,date: 1,description: 1,body: 1,"comments.date": 1,"comments.body": 1,"comments.author.username": 1,"comments.author.avatar": 1,"author.username": 1,"author.avatar": 1
}
}
]);
}
if (!article) throw new Error();
} catch {
return res.status(404).render('errors/404');
}
res.render('articles/article',{
article: article[0]
});
});