How to Flatten Double Arrays in Mongodb

How can I flatten double arrays in mongoDB?

Your data for Countries are not in a good format, so you may consider to convert them. This is a script to flatten the array in Countries field and save it the origin documents that you can run in a mongo shell:

function flattenArray(inArr) {
var ret = [];
inArr.forEach(function(arr) {
if (arr.constructor.toString().indexOf("Array") > -1) {
ret = ret.concat(flattenArray(arr));
} else {
ret.push(arr);
}
});
return ret;
}

db.collection.find({
'Countries': {
'$exists': true
}
}).forEach(function(doc){
doc.Countries = flattenArray(doc.Countries);
db.collection.save(doc);
});

MongoDB flatten arbitrary nested arrays

I agree with @Joe's answer, No straight way to handle this kind of operation in MongoDB, You should think about your schema design as per your query requirement.

If you think you really needed this, you can try MongoDB Defines a custom aggregation function or expression in JavaScript, ​$function and $accumulator,

{
$project: {
​ data: {
​$function: {
​body: function(data) {
​const flatten = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
​return flatten(data);
​},
​args: ["$data"],
​lang: "js"
​}
​}
​}
​}

Playground

IMPORTANT

Executing JavaScript inside an aggregation expression may decrease performance. Only use the $function operator if the provided pipeline operators cannot fulfill your application's needs.

Flatten MongoDB nested array in aggregation

You can use below aggregation. Use $map to format the states array to include phase field.

db.docs.aggregate([
{"$addFields":{
"states":{
"$reduce":{
"input":"$phases",
"initialValue":[],
"in":{
"$concatArrays":[
"$$value",
{"$map":{
"input":"$$this.states",
"as":"state",
"in":{"phase":"$$this.type","type":"$$state.type","time":"$$state.time"}
}}
]
}
}
}
}}
])

Mongo Aggregation Flat nested arrays

Working on the assumption that FieldA in your example is a placeholder that might be multiple fields or different names, you might

  • $project to combine the top level Billings with the $extras array
  • unwind Extras and Billings so each document contains only one
  • Add the ProjectId and ExtraId to the billing object
  • Promote the Billings document to be the root

This will keep any fields in each Billings document, and not require that you know the field names ahead of time.

db.collection.aggregate([
{"$project": {
_id: 0,
ProjectId: 1,
Extras: {
$concatArrays: [
[{ Billings: "$Billings" }],
"$Extras"
]
}
}},
{$unwind: "$Extras"},
{$unwind: "$Extras.Billings"},
{$addFields: {
"Extras.Billings.ExtraId": "$Extras.ExtraId",
"Extras.Billings.ProjectId": "$ProjectId"
}},
{$replaceRoot: {
newRoot: "$Extras.Billings"
}}
])

Playground

Return flattened array from each element in a nested array mongo with aggregation query

I would use $unwind to flatten the array followed by $mergeObjects to combine keys along with $replaceRoot to promote the merge documents to the top.

Something like

db.colname.aggregate([
{$unwind:"$cars"},
{$replaceRoot:{newRoot:{$mergeObjects:[{owner:"$owner"}, "$cars"]}}}
])

Flatten nested arrays using mongodb aggregation in spring

This aggregation will help you achieve your result, except that you have to adapt it with Java driver:

db.countries.aggregate([
{
"$unwind": "$cities"
},
{
"$project": {
"_id": 0,
"cities": 1
}
},
{
"$replaceRoot": {
"newRoot": "$cities"
}
}
])

How to flatted nested keys into the top level object in Mongoose

Maybe something like this using the aggregation framework:

db.collection.aggregate([
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$$ROOT",
"$attributes"
]
}
}
},
{
$project: {
attributes: 0
}
}
])

Explained:

  1. ReplaceRoot with merged object between the root object & attributes
  2. Remove the attributes object from the output.

playground



Related Topics



Leave a reply



Submit