skip to Main Content

I have a documents that looks like this:

_id: ObjectId('...')
name: Team A
players: [
    {
        name: Michael
        position: Goalkeeper
    },
    {
        name: Frank
        position: Defender
    },
    {
        name: Mike
        position: Goalkeeper
    }
]

I want to make an aggregation that simply returns a list of Goalkeeper names, like this..

Players: [
    Michael,
    Mike
]

This is what I have so far:

{
    $match: { name: "Team A" }
},
{ 
   $project: {
       players: {
           $filter: {
               input: "$players",
               cond: {$eq: ["$$this.position", "Goalkeeper"]}
           }
        },
        _id: 0
    }
}

This filters the players Array so it only contains goalkeepers. Now I need to somehow take the names of each object out and store it in another Array. How do I achieve that?

2

Answers


  1. Use $reduce to iterate through the array and use $cond to conditionally $setUnion the entry into the accumulator.

    db.collection.aggregate([
      {
        $project: {
          players: {
            "$reduce": {
              "input": "$players",
              "initialValue": [],
              "in": {
                "$cond": {
                  "if": {
                    $eq: [
                      "$$this.position",
                      "Goalkeeper"
                    ]
                  },
                  "then": {
                    "$setUnion": [
                      "$$value",
                      [
                        "$$this.name"
                      ]
                    ]
                  },
                  "else": "$$value"
                }
              }
            }
          }
        }
      }
    ])
    

    Mongo Playground

    Login or Signup to reply.
  2. You can use also $reduce/$filter as follow:

    db.collection.aggregate([
    {
     $match: {
        name: "Team A"
     }
     },
     {
      "$project": {
        players: {
        "$reduce": {
          input: {
            "$filter": {
              input: "$players",
              cond: {
                $eq: [
                  "$$this.position",
                  "Goalkeeper"
                ]
              }
            }
          },
          "initialValue": [],
          "in": {
            $concatArrays: [
              "$$value",
              [
                "$$this.name"
              ]
            ]
          }
        }
      }
     }
    }
    ])
    

    playground

    Explained:

    1. $filter only the Goalkeeper array objects to provide to $reduce.
    2. $reduce with $concatArrays only the names.
    3. Project only the $reduce-d player names array.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search