0

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!

turivishal
  • 34,368
  • 7
  • 36
  • 59
  • can you add some sample documents instead of image and how you want expected result? in object or array? – turivishal Nov 24 '20 at 12:06
  • That's the sample json content: https://pastebin.com/8er3iPMB The expected result would be just a object with that searched name or at least an array with single entry. e.g: attribute: { "@name": "attributeKey2", "content": "attributeValue2" } – Hubert Stasiuk Nov 24 '20 at 12:21
  • The @name attribute value is an unique. Cannot be repeated in any other array / object – Hubert Stasiuk Nov 24 '20 at 12:22
  • Can you please add the expected output? That' would make things easy – Minsky Nov 24 '20 at 13:27

1 Answers1

1

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

turivishal
  • 34,368
  • 7
  • 36
  • 59
  • Hey Turivishal! Thank you for your answer. I tried to applied that stage to more "productions like" data. It seems that the structure is a little bit more embedded than I expected. I created a new configuration in mongo playground : https://mongoplayground.net/p/m9mwDIeXWRn That top level array is the previous "productAttributes" value, but it seems that there are additional attributeGroup arrays :/ The rest is the same including @ name and content fields in objects, but after research I still could not extract a single field with Produktbasisklasse in the @ name field – Hubert Stasiuk Nov 24 '20 at 14:23
  • In some documents `attribute` field is object and in some its array, is that correct data, or `attribute` field having both type of data? – turivishal Nov 24 '20 at 14:35
  • that's correct. If there are more than 1 attribute - it's an array, but for only one - a json object :/ – Hubert Stasiuk Nov 24 '20 at 14:45
  • i have update the answer and playground link, can you check. you need to pass name value in 3 places for search. as i have commented in code. – turivishal Nov 24 '20 at 14:59