Search code examples
arraysmongodbaggregation-frameworkprojection

MongoDB Aggregation - $filter in projection for embedded arrays


I have a complex structure of JSON object which contain (N) number of embedded arrays. A single entry is an object with two fields : @name and content. I need to filter them in projection stage (without using $unwind) to get one specific object where @name field is equals to specific value:

a

 productCategory: {$filter: {
 input: '$characteristics.attributeGroup.attribute',
 as: 'attribute',
 cond: {
        ...?
 }}

The $characteristics.attributeGroup.attribute input returns the above structure. I was trying to use something like that in $cond: { $eq: ['$$attribute.@name', 'averageRating'] } but it doesn't work.

Could you please help me to find out a solution here?

Thanks in advance!


Solution

  • You can try,

    • $reduce to iterate loop of attributeGroup array, and back merge objects using $mergeObjects
    • check condition if attribute's type is object then again check second condition if @name matched then return values otherwise move to else condition
    • $reduce to iterate loop of attribute array, check condition if name match then return value
    let name = "Artikelhinweise";
    db.collection.aggregate([
      { $match: { "attributeGroup.attribute.@name": name } }, // name pass here
      {
        $project: {
          attributeGroup: {
            $reduce: {
              input: "$attributeGroup",
              initialValue: {},
              in: {
                $mergeObjects: [
                  "$$value",
                  {
                    $cond: [
                      { $eq: [{ $type: "$$this.attribute" }, "object"] },
                      {
                        $cond: [
                          { $eq: ["$$this.attribute.@name", name] }, // name pass here
                          {
                            "@name": "$$this.attribute.@name",
                            "content": "$$this.attribute.content"
                          },
                          "$$value"
                        ]
                      },
                      {
                        $reduce: {
                          input: "$$this.attribute",
                          initialValue: {},
                          in: {
                            $cond: [
                              { $eq: ["$$this.@name", name] }, // name pass here
                              {
                                "@name": "$$this.@name",
                                "content": "$$this.content"
                              },
                              "$$value"
                            ]
                          }
                        }
                      }
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    ])
    

    Playground