Search code examples
mongodbfilterprojection

MongoDB aggregate filter returns null


In MongoDB, I have a messages' collection (find it below):

I'm interested in querying the parent document by id, and say filtering contactedNumberMessages to include only incoming messages (those having direction "in") so I wrote the following code with Mongoose, however contactedNumberMessages is null in the returned data, any clue as to why I'm getting null? Thank you

Messages.aggregate([
    {
      $match: {
        _id: id
      }
    },
    {
      $project: {
        messaging: {
          ourNumber: 1,
          messages: {
            contact: 1,
            contactedNumberMessages: {
              $filter: {
                input: "$contactedNumberMessages",
                as: "message",
                cond: {
                  $eq: ["$$message.direction", "out"]
                }
              }
            }
          }
        }
      }
    }
  ]);
{
  "_id": {
    "$oid": "612f4e32aa56064f1608c2eb"
  },
  "messaging": [
    {
      "ourNumber": "+15123568549",
      "messages": [
        {
          "contact": "+21629000111",
          "contactedNumberMessages": [
            {
              "direction": "out",
              "content": "Hello!",
              "when": {
                "$date": "2021-09-23T23:00:00.000Z"
              },
              "nature": "SMS"
            },
            {
              "direction": "in",
              "content": "Hi!",
              "when": {
                "$date": "2021-09-23T23:00:00.000Z"
              },
              "nature": "SMS"
            }
          ]
        }
      ]
    }
  ]
}

Solution

  • pls refer to example here: https://mongoplayground.net/p/9toRoa_5IE9

    you should use something like below in aggregation:

    [{$match: {
      _id: ObjectId('612f4e32aa56064f1608c2eb')
    }}, {$unwind: {
      path: '$messaging',
    }}, {$unwind: {
      path: '$messaging.messages',
    }}, {$project: {
            messaging: {
        ourNumber: 1,
        messages: {
          contact: 1,
          contactedNumberMessages: {
            $filter: {
              input: "$messaging.messages.contactedNumberMessages",
              as: "message",
              cond: {
                $eq: ["$$message.direction", "out"]
              }
            }
          }
        }
      }
    }}]
    

    As you have nested array within array and sub array that filter stage was not getting correct output, i have added unwind to get the normal array for field:messaging.messages.contactedNumberMessages

    if needed you can again do groupby to ensure you get document in expected format as after unwind it will create multiple documents in aggregation for each documents in array which in unwinded.