skip to Main Content

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",

2

Answers


  1. 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

    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search