Home > Software design >  How do I filter objects and create a list of a specific field from the remaining objects in MongoDB?
How do I filter objects and create a list of a specific field from the remaining objects in MongoDB?

Time:12-15

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?

CodePudding user response:

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

CodePudding user response:

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.
  • Related