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!

4
  • can you add some sample documents instead of image and how you want expected result? in object or array? Commented Nov 24, 2020 at 12:06
  • That's the sample json content: 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" } Commented Nov 24, 2020 at 12:21
  • The @name attribute value is an unique. Cannot be repeated in any other array / object Commented Nov 24, 2020 at 12:22
  • Can you please add the expected output? That' would make things easy Commented Nov 24, 2020 at 13:27

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

4 Comments

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 : 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
In some documents attribute field is object and in some its array, is that correct data, or attribute field having both type of data?
that's correct. If there are more than 1 attribute - it's an array, but for only one - a json object :/
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.