Home > Back-end >  Why doesn't mongoose aggregate method return all fields of a document?
Why doesn't mongoose aggregate method return all fields of a document?

Time:04-02

I have the following document

    [
      {
        "_id": "624713340a3d2901f2f5a9c0",
        "username": "fotis",
        "exercises": [
          {
            "_id": "624713530a3d2901f2f5a9c3",
            "description": "Sitting",
            "duration": 60,
            "date": "2022-03-24T00:00:00.000Z"
          },
          {
            "_id": "6247136a0a3d2901f2f5a9c6",
            "description": "Coding",
            "duration": 999,
            "date": "2022-03-31T00:00:00.000Z"
          },
          {
            "_id": "624713a00a3d2901f2f5a9ca",
            "description": "Sitting",
            "duration": 999,
            "date": "2022-03-30T00:00:00.000Z"
          }
        ],
        "__v": 3
      }
    ]

And I am executing the following aggregation (on mongoplayground.net)

    db.collection.aggregate([
      {
        $match: {
          "_id": "624713340a3d2901f2f5a9c0"
        }
      },
      {
        $project: {
          exercises: {
            $filter: {
              input: "$exercises",
              as: "exercise",
              cond: {
                $eq: [
                  "$$exercise.description",
                  "Sitting"
                ]
              }
            }
          },
          limit: 1
        }
      }
    ])

And the result is the following

    [
      {
        "_id": "624713340a3d2901f2f5a9c0",
        "exercises": [
          {
            "_id": "624713530a3d2901f2f5a9c3",
            "date": "2022-03-24T00:00:00.000Z",
            "description": "Sitting",
            "duration": 60
          },
          {
            "_id": "624713a00a3d2901f2f5a9ca",
            "date": "2022-03-30T00:00:00.000Z",
            "description": "Sitting",
            "duration": 999
          }
        ]
      }
    ]

So my first question is why is the username field not included in the result?

And the second one is why aren't the exercises limited to 1? Is the limit currently applied to the whole user document? If so, is it possible to apply it only on exercises subdocument?

Thank you!

CodePudding user response:

First Question

When you use $project stage, then only the properties that you specified in the stage will be returned. You only specified exercises property, so only that one is returned. NOTE that _id property is returned by default, even you didn't specify it.


Second Question

$limit is also a stage as $project. You can apply $limit to the whole resulting documents array, not to nested array property of one document.


Solution

In $project stage, you can specify username filed as well, so it will also be returned. Instead of $limit, you can use $slice to specify the number of documents that you want to be returned from an array property.

db.collection.aggregate([
  {
    "$match": {
      "_id": "624713340a3d2901f2f5a9c0"
    }
  },
  {
    "$project": {
      "username": 1,
      "exercises": {
        "$slice": [
          {
            "$filter": {
              "input": "$exercises",
              "as": "exercise",
              "cond": {
                "$eq": [
                  "$$exercise.description",
                  "Sitting"
                ]
              }
            }
          },
          1
        ]
      }
    }
  }
])

Working example

  • Related