Home > Software engineering >  Run a loop through an array of objects in the $project pipeline of MongoDB
Run a loop through an array of objects in the $project pipeline of MongoDB

Time:12-29

I have used the $group pipeline and inside it, I have used $addToSet which has created an array of objects which contains two values - {subGenre (string), flag (bool)}. In the next pipeline of $project, I need to run a loop through this array and I need to select only that element of the array where flag is false.

So my code looks like this:

let data = await Books.aggregate(
   [
    {
        $group: {
          _id:  genre,
          price: { $sum: "$price" },
           data: {
            $addToSet: {
              subGenre: "$subGenre",
              flag: "$flagSelectGenre"
            }
          }
        }
       }
      ]
    );

This would return documents like:

    _id: {
      genre: "suspense",
    },
   price: 10210.6,
   data: [
      {
        subGenre: "Thriller",
        flag: false,
      },
      {
        subGenre: "jumpScare",
        flag: true,
      }
      {
        subGenre: "horror",
        flag: false,
      }
    ]

After this, I need to run a $project pipeline where I have to only project that element of the data array where the flag is true. The flag will be true for only one element.

$project: {
          price: "$price",
          subGenre: {$...... } // some condition on data array??
}

The final output should look like this:

   price: 10210.6,
   subGenre: "jumpScare",

CodePudding user response:

You can do it like this:

  • $filter - to filter items from data array, where flag property is equal to true.
  • $first - to get first item from above array.
  • $getField - to get value of subGenre property of the above item.
db.collection.aggregate([
  {
    "$project": {
      "_id": 0,
      "price": 1,
      "data": {
        "$getField": {
          "field": "subGenre",
          "input": {
            "$first": {
              "$filter": {
                "input": "$data",
                "cond": "$$this.flag"
              }
            }
          }
        }
      }
    }
  }
])

Working example

CodePudding user response:

You can use $filter array operator to loop and filter elements by required conditions,

  • $filter to iterate loop of data array, if flag is true then return element
  • $let to define a variable and store the above filter result
  • $first to return the first element from the filtered result, you can also use $arrayElemAt if you are using lower version of the MongoDB
  {
    $project: {
      price: 1,
      subGenre: {
        $let: {
          vars: {
            data: {
              $filter: {
                input: "$data",
                cond: "$$this.flag"
              }
            }
          },
          in: { $first: "$$data.subGenre" }
        }
      }
    }
  }

Playground


Another approach using $indexOfArray and $arrayElemAt operators,

  • $indexOfArray will find the matching element index of the array
  • $arrayElemAt to get specific element by specifying the index of the element
  {
    $project: {
      price: 1,
      subGenre: {
        $arrayElemAt: [
          "$data.subGenre",
          { $indexOfArray: ["$data.flag", true] }
        ]
      }
    }
  }

Playground

  • Related