MongoDB подсчитывает все лайки и публикации для одного пользователя с помощью конвейера агрегирования

#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}
    }}
])
 

Игровая площадка