Flattening an array of objects javascript - javascript

I have the folders in a json file as follows:
[{ "name": "Knowledge Base",
"files": [
{
"name": "Documents",
"files": [
{
"name": "Quarterly Results"
}
]
},
{
"name": "Favourites",
"files": [
{
"name": "Brawl Stars",
"files": [
{
"name": "NS dying in 5 seconds"
},
{
"name": "Josiah raping NS"
}
]
},
{
"name": "Coding",
"files": [
{
"name": "Coding is so fun"
},
{
"name": "I love svelte",
"files": [
{
"name": "REPL"
},
{
"name": "oh nooo"
}
]
}
]
},
{
"name": "Favourites 1"
},
{
"name": "Favourites 2"
},
{
"name": "Favourites 3"
}
]
},
{
"name": "Knowledge Base 1"
}
]
}]
How do I flatten this array of objects such that I would get the desired output below such that, ignoring files and only caring about folders (which have files inside):
All possible routes that can be taken by going through all folders, ignoring files with no other files inside them.
Knowledge Base > Documents
Knowledge Base > Favourites > Brawl Stars
Knowledge Base > Favourites > Coding
Knowledge Base > Favourites > Coding > I love svelte
I figured out using a recursive function, but I dont know how to go from there.

const rootFiles = [{"name":"Knowledge Base","files":[{"name":"Documents","files":[{"name":"Quarterly Results"}]},{"name":"Favourites","files":[{"name":"Brawl Stars","files":[{"name":"NS dying in 5 seconds"},{"name":"Josiah raping NS"}]},{"name":"Coding","files":[{"name":"Coding is so fun"},{"name":"I love svelte","files":[{"name":"REPL"},{"name":"oh nooo"}]}]},{"name":"Favourites 1"},{"name":"Favourites 2"},{"name":"Favourites 3"}]},{"name":"Knowledge Base 1"}]}]
function getDirectoryPaths(files) {
return files.flatMap(({name, files: childFiles}) => childFiles ? [
name,
...getDirectoryPaths(childFiles).map(childPath=>`${name}>${childPath}`)
] : [])
}
console.log(getDirectoryPaths(rootFiles))
// or, if you don't want the top-level directory listed:
console.log(getDirectoryPaths(rootFiles).slice(1))

In your recursive function just check if object has files property:
const data = [{ "name": "Knowledge Base",
"files": [
{
"name": "Documents",
"files": [
{
"name": "Quarterly Results"
}
]
},
{
"name": "Favourites",
"files": [
{
"name": "Brawl Stars",
"files": [
{
"name": "NS dying in 5 seconds"
},
{
"name": "Josiah raping NS"
}
]
},
{
"name": "Coding",
"files": [
{
"name": "Coding is so fun"
},
{
"name": "I love svelte",
"files": [
{
"name": "REPL"
},
{
"name": "oh nooo"
}
]
}
]
},
{
"name": "Favourites 1"
},
{
"name": "Favourites 2"
},
{
"name": "Favourites 3"
}
]
},
{
"name": "Knowledge Base 1"
}
]
}];
function flatten(obj, parent = "")
{
parent += obj.name + ">"; //append current folder name
let result = [];
if (obj.files)
{
result = obj.files
.filter(file => file.files) //only leave folders
.map(file => parent + file.name);//add names
}
if (Array.isArray(obj.files))
result = result.concat(...obj.files.map(folder => flatten(folder, parent))); //recursivly call flatten for next subfolder
return result;
}
const dataFlat = data.reduce((a,b) => (a.push(...flatten(b)), a), []);
console.log(dataFlat);

Related

How to iterate an array with key which appears different combination in nested array in javascript

i have an array structure like below, which has combinedPorts as key with nested array. i can able to iterate and display the properties with .map function in ES6 if all the object has same number of combinedPorts key. But here in the first object the combinedPorts array appears three time whereas in second object the combinedPorts array appears twice. How to iterate the combinedPorts key if it appears different from one object to other.
[
{
"name": "Test Source",
"combinedPorts": [
{
"name": "PortGroup_1",
"templateId": "edfb5b72ec580b129465ea0e8029bad3",
"type": "SourcePorts",
"combinedPorts": [
{
"name": "Source_1",
"templateId": "2355fc02e18cd48c6b487aa8b6f75959",
"type": "SourcePorts",
"combinedPorts": [
{
"name": "Sami_TestSource",
"templateId": "0007ad49ea9b02b309a1248592a01981",
"type": "SourcePorts"
},
],
}
],
}
],
"portGroupInfo": []
},
{
"name": "Test Source",
"combinedPorts": [
{
"name": "PortGroup_1",
"templateId": "edfb5b72ec580b129465ea0e8029bad3",
"type": "SourcePorts",
"combinedPorts": [
{
"name": "Source_1",
"templateId": "2355fc02e18cd48c6b487aa8b6f75959",
"type": "SourcePorts"
}
],
}
],
"portGroupInfo": []
}
]
can someone guide me achieve this using ES6. Thanks in advance.
I would suggest using a recursive approach, this will deal with any level of nesting.
We'd create a function getNestedArrays() that will combine the elements in nested arrays of a given name: arrayName.
At each level, if we find the right array, we'll add the array to our output without any child arrays, then continue walking through the structure.
let input = [ { "name": "Test Source", "combinedPorts": [ { "name": "PortGroup_1", "templateId": "edfb5b72ec580b129465ea0e8029bad3", "type": "SourcePorts", "combinedPorts": [ { "name": "Source_1", "templateId": "2355fc02e18cd48c6b487aa8b6f75959", "type": "SourcePorts", "combinedPorts": [ { "name": "Sami_TestSource", "templateId": "0007ad49ea9b02b309a1248592a01981", "type": "SourcePorts" }, ], } ], } ], "portGroupInfo": [] }, { "name": "Test Source", "combinedPorts": [ { "name": "PortGroup_1", "templateId": "edfb5b72ec580b129465ea0e8029bad3", "type": "SourcePorts", "combinedPorts": [ { "name": "Source_1", "templateId": "2355fc02e18cd48c6b487aa8b6f75959", "type": "SourcePorts" } ], } ], "portGroupInfo": [] } ]
function getNestedArrays(obj, arrayName) {
let result = [];
for(let key in obj) {
if (obj[key] && typeof(obj[key]) === 'object') {
if ((key === arrayName) && Array.isArray(obj[key])) {
// We've found our array, add without child arrays...
result.push(...obj[key].map(({ [arrayName]: x, ...row}) => ({ ...row })))
}
result.push(...getNestedArrays(obj[key], arrayName));
}
}
return result;
}
console.log(input.map(obj => {
obj.combinedPorts = getNestedArrays(obj, 'combinedPorts');
return obj;
}));
.as-console-wrapper { max-height: 100% !important; }

Concatenating child array to parent

Right now I have an array of object with children that also have an array of objects.
[
{
"code": "mock-code",
"name": "mock-name",
"children": [
{
"code": "mock-child-code",
"name": "mock-child-name",
},
{
"code": "mock-child-code",
"name": "mock-child-name",
},
],
},
{
"code": "mock-code",
"name": "mock-name",
"children": [],
},
{
"code": "mock-code",
"name": "mock-name",
"children": [
{
"code": "mock-code",
"name": "mock-name",
}
],
}
]
I want to extract the children array and concat them to the parent array like below.
[
{
"code": "m1",
"name": "mock-name",
"children": [
{
"code": "mc-1",
"name": "mn-1",
},
{
"code": "mc-2",
"name": "mn-2",
},
],
},
{
"code": "m2",
"name": "mock-name",
"children": [],
},
{
"code": "mm3",
"name": "mock-name",
"children": [
{
"code": "mc-3",
"name": "mn-3",
}
],
}
{
"code": "mc-1",
"name": "mn-1",
},
{
"code": "mc-2",
"name": "mn-2",
},
{
"code": "mc-3",
"name": "mn-3",
}
]
What are someways to do this. I'm currently looping though the child array creating a new array checking if it's not empty. It all seems a bit messy. Is there a clean way to do this?
let fullList = New Array()
parentData.forEach(element => {
if (!!element.children.length) {
fullList.push(element.children);
}
});
return parentData.concat(fullList);
This isn't giving me the desired results since it's adding another array to the parent object but this is where I am at.
const newArray = originalArray.flatMap(element => [element, ...element.children])
This should do it, and as a bonus will preserve the order (parent1, parent1's children, parent2, parent2's children etc.)
Of course, this works if you have only one level of nesting. If you have greater depth level, that would be a bit more complex, probably using Array.prototype.reduce().

javascript map object multidimension

i have this data structure:
tree = [
{
"name": "Men Section",
"categories": [
{
"name": "Clothings",
"Subcategories": [
{
"name": "Jackets",
"products": [
{
"name": "jacket 01",
"price": 100
},
{
"name": "jacket 02",
"price": 140
},
// ..and so on
]
]
},
// ..and so on
]
} // ..and so on
]
how can i add new property in products item isSelected: false in javascript (ES5 or ES6 is fine) so the object will be
{
"name": "jacket 01",
"price": 100,
"isSelected": false
}
?
It could be useful, it works for me
tree.forEach(base => {
base.categories.forEach(categories => {
categories.Subcategories.forEach(subCategory =>{
subCategory.products.forEach(product => product.isSelected = false)
})
});
});
so yeah, i should traverse deep to the object with nested foreach. i came up with this:
tree.categories.forEach(function (category) {
category.subcategories.forEach(function (subcategory) {
subcategory.products.forEach(function (product) {
product.isSelected = false;
})
})
})
thanks for the enlightment

filter on the basis of a value in an array in where

I'm querying data, where the structure is something like this.
I have two models, FoodDrinks and Cuisines. They have many to many relation.
Now on the following query
{
"filter": {
"include": "cuisines"
}
}
I am getting the following results.
[
{
"id": 1,
"name": "Biryani",
"cuisines": [
{
"id": 1,
"name": "Mughlai"
},
{
"id": 2,
"name": "North Indian"
},
{
"id": 3,
"name": "Afghani"
}
]
},
{
"id": 2,
"name": "Chhole Bhature",
"cuisines": [
{
"id": 2,
"name": "North Indian"
}
]
},
{
"id": 3,
"name": "Amritsari Naan",
"cuisines": [
{
"id": 2,
"name": "North Indian"
},
{
"id": 6,
"name": "Punjabi"
},
]
}
]
Now I want only those food drinks which have cuisines from the following array.
let cuisinesIDs = ["1", "2"]
What will the following query for that?
I guess something like the below should work:
{
"filter": {
"include": "cuisines"
},
"where": {
"cuisines.id": {
"inq": cuisinesIDs
}
}
}
It might be the same answer as #Behrooz, but I would try:
{
"filter": {
"include": {
relation: 'cuisines',
scope: {
where: {
id: {inq: cuisinesIDs}
}
}
}
}
}

Adding object to parent array based on IDs using Lodash

So I'm having an issue - I'm getting some data from our internal API at work, but it's not in the correct format I need to do what I have to do, so I have to make some transformations.
For this, I decided to use Lodash, however I'm stuck now.
Basically, I'm working with orders, but some of the products are addons to a parent product. I've managed so far to separate these two types of products, but I don't know how I should go about adding an "addons" array as a child to the parent product with matching ID.
Here's a basic stripped example of the output I'd like:
{
"order": {
"orderLines: [
{
"orderId": "foo",
"addons" [
{
...
}
]
},
{
...
}
]
}
}
And here's my current code:
// TODO:
// Match addons to products based on "connectedTo" => "id", then add matching addons as a new array on parent object
// Base data
const data = {
"order": {
"shopOrderId": "19LQ89H",
"createDate": "2017-10-24T13:09:22.325Z",
"orderLines": [
{
"orderId": "19LQ89H",
"product": {
"productName": "Paintball",
},
"id": "59ef3b8036e16f1c84787c1f",
"stringId": "59ef3b8036e16f1c84787c1f"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "Ølsmagning",
},
"id": "59ef3b8036e16f1c84787c20",
"stringId": "59ef3b8036e16f1c84787c20"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "CD-indspilning",
},
"id": "59ef3b8136e16f1c84787c21",
"stringId": "59ef3b8136e16f1c84787c21"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "Julefrokost",
},
"id": "59ef3b8236e16f1c84787c22",
"stringId": "59ef3b8236e16f1c84787c22"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "Hummer Limousine",
},
"id": "59ef3b8236e16f1c84787c23",
"stringId": "59ef3b8236e16f1c84787c23"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c23",
"product": {
"productName": "Ekstra kørsel 400",
},
"id": "59ef3b8236e16f1c84787c24",
"stringId": "59ef3b8236e16f1c84787c24"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c23",
"product": {
"productName": "Drikkevarer",
},
"id": "59ef3b8236e16f1c84787c25",
"stringId": "59ef3b8236e16f1c84787c25"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c23",
"product": {
"productName": "Drikkevarer",
},
"id": "59ef3b8236e16f1c84787c26",
"stringId": "59ef3b8236e16f1c84787c26"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c22",
"product": {
"productName": "Snaps ad libitum",
},
"id": "59ef3b8236e16f1c84787c27",
"stringId": "59ef3b8236e16f1c84787c27"
}
],
"travelTimes": [
{
"id": "59ef3b8036e16f1c84787c1f-59ef3b8036e16f1c84787c20",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c1f",
"partyPlanToEventId": "59ef3b8036e16f1c84787c20",
"start": "2017-11-15T17:02:59",
"end": "2017-11-15T17:30:00",
"travelTimeString": "27 min.",
"travelTimeMinutes": 28,
"exceedsAvailableTime": false
},
{
"id": "59ef3b8036e16f1c84787c20-59ef3b8136e16f1c84787c21",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c20",
"partyPlanToEventId": "59ef3b8136e16f1c84787c21",
"start": "2017-11-15T19:52:12",
"end": "2017-11-15T20:00:00",
"travelTimeString": "8 min.",
"travelTimeMinutes": 8,
"exceedsAvailableTime": false
},
{
"id": "59ef3b8036e16f1c84787c20-59ef3b8236e16f1c84787c22",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c20",
"partyPlanToEventId": "59ef3b8236e16f1c84787c22",
"start": "2017-11-15T12:30:00",
"end": "2017-11-15T13:00:00",
"travelTimeString": "8 min.",
"travelTimeMinutes": 8,
"exceedsAvailableTime": true
},
{
"id": "59ef3b8036e16f1c84787c20-59ef3b8236e16f1c84787c23",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c20",
"partyPlanToEventId": "59ef3b8236e16f1c84787c23",
"start": "2017-11-15T08:30:00",
"end": "2017-11-15T09:00:00",
"travelTimeString": "3 min.",
"travelTimeMinutes": 4,
"exceedsAvailableTime": true
}
],
"id": "59ef3b8236e16f1c84787c28",
"stringId": "59ef3b8236e16f1c84787c28"
}
}
// Transform data
const travelTimes = data.order.travelTimes.map(item => _.omit(item, ['id']) )
const orderLines = _.merge(data.order.orderLines, travelTimes)
const order = _.omit(data.order, ['orderLines', 'travelTimes'])
const orders = _.assign(order, { orderLines })
const addonGroups = _.groupBy(order.orderLines, 'connectedTo')
const addons = _.omit(addonGroups, 'undefined')
const products = _.pick(addonGroups, 'undefined')
const productGroups = _.groupBy(products.undefined, 'stringId')
console.log(productGroups) // All parent products
console.log(addons) // All addon products
const arr1 = _.values(_.flatMap(productGroups))
const arr2 = _.values(_.flatMap(addons))
Code on Codepen.io
Any help is greatly appreciated!
Let me know if I need to explain in further detail.
Not sure if I understood correctly what the expected result is, but I gave it a try anyway.
const orderLines = _(data.order.orderLines)
.map(item => {
if (!item.connectedTo) return _.assignIn(item, { addons: [] });
const match = _.find(data.order.orderLines, { id: item.connectedTo });
match.addons = match.addons || [];
match.addons.push(item);
return null;
})
.compact()
.value();
Check the output here: https://codepen.io/andreiho/pen/YEzQRd?editors=0012

Categories