MQL doesn't have functions, so we can't recur, if we find a array.
Maybe there is a way to do it with MQL and 1 query.
But there is way to do it fast with more than 1 query.
The bellow example is 1 level/query.
With small change it can do 10 level/query or 100 level/query etc
so only 1 query will be needed, but we will do some redadent attempts to flatten arrays even if they are empty.
First 1 small modification.
Add 1 field on all documents "all-items": [{"id": "$id","type": "$type"}]
and removed the top level "id" and "type". Like bellow
aggregate(
[ {
"$project" : {
"all-items" : [ {
"id" : "$id",
"type" : "$type"
} ],
"items" : 1
}
} ]
)
Modified data
[
{
"all-items": [
{
"id": "1",
"type": "panel"
}
],
"items": [...like it was...]
}
]
And now we can do it with multiple queries 1 per/level
First call, code example
Second call, code example, with the result of first call
Third call we dont need, while will be false.
In each call we do $out, and we aggregate on the result of previous call.
while(there_is_1_document_with_not_empty_items[]) (send 1 find query)
db.collection.aggregate([
{
"$addFields": {
"level-nlevel": {
"$reduce": {
"input": "$items",
"initialValue": [
[],
[]
],
"in": {
"$let": {
"vars": {
"info": "$$value",
"i": "$$this"
},
"in": {
"$let": {
"vars": {
"level": {
"$arrayElemAt": [
"$$info",
0
]
},
"nlevel": {
"$arrayElemAt": [
"$$info",
1
]
}
},
"in": [
{
"$concatArrays": [
"$$level",
[
{
"id": "$$i.id",
"type": "$$i.type"
}
]
]
},
{
"$cond": [
{
"$isArray": [
"$$i.items"
]
},
{
"$concatArrays": [
"$$nlevel",
"$$i.items"
]
},
"$$nlevel"
]
}
]
}
}
}
}
}
}
}
},
{
"$project": {
"all-items": {
"$concatArrays": [
"$all-items",
{
"$arrayElemAt": [
"$level-nlevel",
0
]
}
]
},
"items": {
"$arrayElemAt": [
"$level-nlevel",
1
]
}
}
}
])
This flattens per document(no $unwind is used), if you want to flatten all collection, $unwind one time after the while ends the $all-items.