6

I have about MongoDB in unwind operator.

So, I have document like this.

{
    "name": "abc",
    "report": {
        "_2019": {
            "May": {
                "_9": {
                    "DATA": [{
                            "image": "xyz.png",
                            "object": true
                        },
                        {
                            "image": "abc.png",
                            "object": true
                        }
                    ]
                },
                "_10": {
                    "DATA": [{
                            "image": "ejf.png",
                            "object": false
                        },
                        {
                            "image": "qwe.png",
                            "object": false
                        }
                    ]
                }
            },
            "June": {
                "_1": {
                    "DATA": [{
                        "image": "jsk.png",
                        "object": false
                    }]
                }
            }
        },
        "_2020": {
            "January": {
                "_30": {
                    "DATA": [{
                        "image": "hhg.png",
                        "object": false
                    }]
                }
            }
        }
    }
}

And want to format the output for something like this

[{
    "image": "xyz.png",
    "object": true
}, {
    "image": "abc.png",
    "object": true
}, {
    "image": "ejf.png",
    "object": false
}, {
    "image": "qwe.png",
    "object": false
}, {
    "image": "jsk.png",
    "object": false
}, {
    "image": "hhg.png",
    "object": false
}]

The first thing i found is that using unwind, but it only accept array. And the second is using foreach in the programming-side. But i think it's not effective. Is this possible? Thank you.

1 Answer 1

3

The problem here is that the keys like _2020 or January or _30 are dynamically generated. To access subdocuments from DATA level you need to get there by using $objectToArray and $map to take values from key-value pairs. After each of these steps you need $unwind and then in the last step you can run $replaceRoot to promote documents from DATA into root level:

db.col.aggregate([
    {
        $project: {
            data: {
                $map: {
                    input: { $objectToArray: "$report" },
                    in: "$$this.v"
                }
            }
        }
    },
    { $unwind: "$data" },
    {
        $project: {
            data: {
                $map: {
                    input: { $objectToArray: "$data" },
                    in: "$$this.v"
                }
            }
        }
    },
    { $unwind: "$data" },
    {
        $project: {
            data: {
                $map: {
                    input: { $objectToArray: "$data" },
                    in: "$$this.v"
                }
            }
        }
    },
    { $unwind: "$data" },
    { $unwind: "$data.DATA" },
    {
        $replaceRoot: {
            newRoot: "$data.DATA"
        }
    }
])

Mongo Playground

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

4 Comments

Wow. What a rough query. It worked but I still have to learn more about how it works. Thank you.
@Skipm3 consider it as a way to unwrap an array that's nested three levels deep and you dont know the keys (can't build a path like level1.level2.level3). Let me know if something is unclear for you
Anyway i'm trying to learn the query. Why this query removes the year (2019 and 2020) data? Is it because $objectToArray operator?
@Skipm3 yes, try to read the docs, there's a lot of examples of how it works as a "one-step" aggregation

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.