I was building a chat server, where I need to get the number of messages that are marked as seen: false
.
below is my schema,
const ChatSchema = mongoose.Schema({
chatId: { type: String, required: true, unique: true },
messages: [
{
message: { type: String, required: true },
sendBy: { type: String, required: true },
sendTo: { type: String, required: true },
seen: { type: Boolean, default: false },
date: { type: Date, default: Date.now()}
},
],
})
I have tried the following code but it always returns 1
const unSeenCount=await Chat.find({ chatId: chatId },
{ messages : { $elemMatch : { seen : false } } })
console.log(`unseen count is ${unSeenCount.length}`);
I think it only gets the documents with the
query { chatId: chatId }
3
Answers
try using filter instead of find:
You have to calculate from projection,
findOne
method because you want one chat’s messages countchatId
condition in the query$filter
to iterate loop ofseen
array from messages and check is any false$size
to count to total elements in above-filtered arraylean()
at the end, and it will return javascript object instead of mongoose documentPlayground
If you use
$elemMatch
, it will return you all documents that satisfy that criteria. Therefore if document has an array that satisfy that criteria, the whole document will be returned. The MongoDB will not "count" how much appereances are there in an array.Your query will return you either 0 or 1, depends if there is at least one message with
seen : false
in an array or not.You can use
unwind
operation: MongoDB: Count of matching array elements . It will allow you to work with objects inside array in same way as with documents. It is not very efficient though, so if you have a lot of messages and you do this operation often, it can consume a lot of MongoDB resources. So if you need to do this (or similar operations) with messages frequently, it is better to create separate collection for messages.