I have chat, admin,user and message entities. chat has reference of user and admin, message has reference on chat. Message has boolean property called viewed. So I am trying to get chats for admin with user data populated and the count of unviewed messages.
Chat.aggregate([
{
$match: {
admin: new Types.ObjectId(admin.id),
},
},
{
$lookup: {
from: "admins",
localField: "admin",
foreignField: "_id",
as: "admin",
},
},
{ $unwind: "$admin" },
{
$lookup: {
from: "users",
localField: "user",
foreignField: "_id",
as: "user",
},
},
{ $unwind: "$user" },
{
$lookup: {
from: "messages",
localField: "_id",
foreignField: "chat",
as: "messages",
},
},
//following match statement doesn't work
// {
// $match: {
// "messages.viewed": false,
// //"messages.reciever":new Types.ObjectId(admin.id),
// },
// },
{
$project: {
id: "$_id",
"admin.id": "$admin._id",
"admin.email": "$admin.email",
"admin.vendorId": "$admin.vendorId",
"user.fullName": 1,
"user.id": "$user._id",
"user.phoneNumber": 1,
"unreadMsgs": {
$size: {
$filter: {
input: "$messages",
as: "message",
cond: { $eq: ["$$message.viewed", false] },
},
},
},
},
},
]).exec();
the commented part of the code (2nd match section seems not working). while there are unwieved messages code was working correctly, when there is no unviewed messages it returns empty array so then commented second mathc statement then everything started working as expected. The question is how can i get count of unread msgs within match not performing additional filtering operations?
Here are Chat Schema
const chatSchema = new Schema(
{
user: { type: Schema.Types.ObjectId, ref: User },
admin: { type: Schema.Types.ObjectId, ref: Admin },
product: { type: Schema.Types.ObjectId, ref: Product },
},
{
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
},
},
}
);
Here is Message Schema
const messageSchema = new Schema(
{
sender: { type: Schema.Types.ObjectId, required: true, ref: User },
reciever: { type: Schema.Types.ObjectId, required: true, ref: User },
chat: { type: Schema.Types.ObjectId, required: true, ref: Chat },
message: String,
file: String,
viewed:{type:Boolean, default:false}
},
{
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
},
},
timestamps: true,
}
);
User and Admin Schemas
const adminSchema = new Schema(
{
email: String,
password: String,
vendorId: { type: Schema.Types.ObjectId, ref: "Vendor" },
online:{type:Boolean, default:false},
super: { type: Boolean, default: false },
},
{
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
},
},
}
);
const userSchema = new Schema(
{
fullName: String,
password: String,
phoneNumber: Number,
avatar: String,
gender: String,
birthdate: Date,
online:{type:Boolean, default:false},
basket:[{type:Schema.Types.ObjectId, ref:Product}]
},
{
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
},
},
}
);
The $match stage matches documents, it does not filter the contents of an array.
In the preceding $lookup all of the messages are fetched from the messages collection and place in an array in the 'messages' field.
The $match will then select each document that contains at least one unviewed message. If there are no unviewed messages, the entire document is eliminated from the pipeline.
Since you already filter the array in the $project stage, that $match stage is completely unnecessary.