skip to Main Content

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


  1. try using filter instead of find:

    const unSeenCount=await Chat.filter({ chatId: chatId }, 
            { messages : { $elemMatch : { seen : false } } })
        
        console.log(`unseen count is ${unSeenCount.length}`);
    
    Login or Signup to reply.
  2. You have to calculate from projection,

    • use findOne method because you want one chat’s messages count
    • check just chatId condition in the query
    • add projection
      • $filter to iterate loop of seen array from messages and check is any false
      • $size to count to total elements in above-filtered array
    • add lean() at the end, and it will return javascript object instead of mongoose document
    const unSeenCount = await Chat.findOne(
      { chatId: chatId },
      {
        count: {
          $size: {
            $filter: {
              input: "$messages.seen",
              cond: { $eq: ["$$this", false] }
            }
          }
        },
        // add more fields if you need them in the result.
      }
    ).lean();  
    
    console.log(`unseen count is ${unSeenCount.count}`);
    

    Playground

    Login or Signup to reply.
  3. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search