#javascript #mongodb #mongoose
Вопрос:
Мне нужна конечная точка, которая возвращает информацию о пользователе, количество отправленных им сообщений и сумму всех лайков, полученных их сообщениями.
Я использую MongoDB
для своей базы данных вместе с Mongoose
моим Node
сервером.
Это мои модели:
var userSchema = new Schema({
'username' : String,
'email' : String,
'password' : String
});
var photoSchema = new Schema({
'text' : String,
'path' : String,
'timestamp': Number,
'postedBy' : {type: Schema.Types.ObjectId, ref: "user"}
});
var likeSchema = new Schema({
'timestamp' : Number,
'photo' : {type: Schema.Types.ObjectId, ref: 'photo'},
'user' : {type: Schema.Types.ObjectId, ref: 'user'}
});
Я уже сделал это с помощью Javascript и нескольких запросов:
// Get user
let user = await userModel.findOne({_id: mongoose.Types.ObjectId(id)})
.select("_id, username")
.lean()
.exec();
// Get all users photos
let photos = await photoModel.find({postedBy: mongoose.Types.ObjectId(user._id)})
.select("_id")
.exec();
// Sum likes for all photos
let likes = 0;
for (let i = 0; i < photos.length; i )
likes = (await likeModel.find({photo: photos[i]._id}).exec()).length;
Но я хочу попробовать это с помощью конвейера aggregate. Это моя неудачная попытка:
let user = await userModel.aggregate(
[
{
$match: {_id: mongoose.Types.ObjectId(id)}
},
{
$unset: ["email", "password", "__v"]
},
{
$lookup: {
from: "photos",
localField: "_id",
foreignField: "postedBy",
as: "photos"
}
},
{
$lookup: {
from: "likes",
localField: "photos._id",
foreignField: "photo",
as: "likes"
}
},
{
$unwind: "$photos"
},
{
$group: {
_id: "$_id",
username: {$first: "$username"},
postCount: {$sum: 1},
likeCount: {$sum: 1}
}
}
]);
Я не знаю, как получить количество лайков за каждый пост с фотографией. Возможно ли это в одном конвейере агрегации?
Имело бы больше смысла создавать его с несколькими конвейерами аггегации или даже просто с несколькими запросами?
Комментарии:
1. Ваш запрос работает нормально, нет!!… можете ли вы объяснить, с какой проблемой вы сталкиваетесь mongoplayground.net/p/rOw5podguIP
Ответ №1:
Если вы используете $size
для получения размера каждого массива, вам не понадобятся этапы unwind
или group
.
[
{$match: {_id: mongoose.Types.ObjectId(id)}},
{$lookup: {
from: "photos",
localField: "_id",
foreignField: "postedBy",
as: "photos"
}},
{$lookup: {
from: "likes",
localField: "photos._id",
foreignField: "photo",
as: "likes"
}},
{$project: {
likeCount: {$size:"$likes"},
postCount: {$size:"$photos"}
}}
]
С другой стороны, поскольку единственное поле , которое вы получаете из коллекции пользователей _id
, — это то, которое у вас уже есть, вы можете пропустить сопоставление и поиск и просто объединить коллекцию фотографий напрямую:
photoModel.aggregate([
{$match: {postedBy: mongoose.Types.ObjectId(id)}},
{$lookup: {
from: "likes",
localField: "_id",
foreignField: "photo",
as: "likes"
}},
{$group: {
_id: "$postedBy",
likeCount: {$sum:{$size:"$likes"}},
postCount: {$sum:1}
}}
])