First, let me explain what I want to do.
I have tree-like data structure, with arbitrary depth from which i want to make a list of all non-leaf branches which I pass as props to Child component.
Data set and recursive function are bellow.
Problem:
I get double data in array! I noticed that function getBranches() is called also in chrome VM and it just appends same data again to already existing array. See pic bellow.
Is my approach fundamentally wrong? What to do?
const treeData = {
'first-level-node-1': { // key
label: 'Regija',
type: TYPES[1],
index: 0, // rendering order
url: 'http://opa.com',
nodes: {
'second-level-node-1': {
label: 'Bolnica BN',
index: 0,
type: 1,
nodes: {
'third-level-node-1': {
label: 'Konektor Sysmex',
index: 0,
nodes: {},
type: TYPES[0]
},
},
},
},
},
'first-level-node-2': {
label: 'Regija 2',
index: 1,
type: TYPES[1],
nodes: {
'2-1': {
label: 'Dz Trebinje',
index: 0,
type: 1,
nodes: {
'3-1': {
label: 'Konektor Biomerux',
index: 0,
hasNodes: false,
type: TYPES[0],
}
}
}
}
},
};
My getBranches() function:
const getBranches = (treeData) => {
console.log('i= ',i++)
Object.keys(treeData).forEach((key) => {
if (treeData[key].type!==TYPES[0]) {
branches.push({key: key, label: treeData[key].label});
console.log({key: key, label: treeData[key].label})
treeData[key].nodes && getBranches(treeData[key].nodes)
};
});
return [...branches];
};
My Component:
const Sites = () => {
const branches = getBranches(treeData);
console.log(branches);
//const [data, setData] = useState(treeData);
return (
<Container fluid="md">
<Row>
<Col>
<MyTreeView data={treeData}/>
</Col>
<Col>
<BranchView
sites={treeData}
parentList={branches}
/>
</Col>
</Row>
</Container>
);
};
Some additional info:
branch vs leaf is distinguished by property type
The Picture. Notice the i s
I'm guessing the problem is simply that you don't declare branches inside your function, making it a global variable. So the next time the function is run, you're appending to it. Adding a const declaration should probably do.
That said, I think you can simplify getBranches in a clean manner:
const getBranches = (o) => Object .entries (o) .flatMap (
([key, {label, type, nodes}]) => [
... (type == TYPES [0] ? [] : [{key, label}]),
... (nodes ? getBranches (nodes) : [])
]
)
const TYPES = [0, 1]
const treeData = {"first-level-node-1": {label: "Regija", type: TYPES[1], index: 0, url: "http: //opa.com", nodes: {"second-level-node-1": {label: "Bolnica BN", index: 0, type: 1, nodes: {"third-level-node-1": {label: "Konektor Sysmex", index: 0, nodes: {}, type: TYPES[0]}}}}}, "first-level-node-2": {label: "Regija 2", index: 1, type: TYPES[1], nodes: {"2-1": {label: "Dz Trebinje", index: 0, type: 1, nodes: {"3-1": {label: "Konektor Biomerux", index: 0, hasNodes: false, type: TYPES[0]}}}}}}
console .log (getBranches (treeData))
.as-console-wrapper {max-height: 100% !important; top: 0}
Related
I want to filter an array of objects based on a boolean value, so it returns new array of objects that only contains objects with "true" value.
here is my base array:
const extrasList = [
{key: 0, name: "extraNew1", price: 20, active: true },
{key: 1, name: "extraNew2", price: 100, active: false },
{key: 2, name: "extraNew3", price: 400, active: false },
]
here is how I used .filter method to get only "active: true" objects:
const activeExtras = extrasList.filter((extra) => {
return extra.active;
});
and now, to display just names in objects, I used .map method:
const aExtrasList = activeExtras.map((extra) => {
return (
<div key={extra.key}>
<p>{extra.name} </p>
</div>
);
})
I expected React to render "extraNew1", but instead I got "[object Object]"... what am I missing?
Edit: The code above renders fine, the problem occurs when I try to put it inside of this variable:
const toSend = [`name: ${name} - model: ${activeModel} - extra: - ${aExtrasList}`];
Note: name and activeModel are declared in no relation to aExtrasList.
const extrasList = [
{key: 0, name: "extraNew1", price: 20, active: true },
{key: 1, name: "extraNew2", price: 100, active: false },
{key: 2, name: "extraNew3", price: 400, active: false },
]
const activeExtras = extrasList.filter((extra) => {
return extra.active;
});
return(
<>
{
activeExtras.map(extra => {
return(
<div key={extra.key}>
<p>{extra.name} </p>
</div>
)
})
}
</>
);
Apologies if title is not clear.
I am using json2csv npm package to prepare csv from json object and this package allows us to add a hook to transform object before actual csv line is prepared.
I only need to manipulate two properties out of all. How can I do this effectively? My code feels too bloated.
const {
Parser: Json2csvParser,
transforms: { unwind },
} = require('json2csv');
const json2csvFields = [
{ value: 'root.filename', label: 'File Name' },
{ value: 'issue.root.priority', label: 'Priority' },
{ value: 'issue.root.url', label: 'URL' },
{ value: 'issue.root.startline', label: 'Start Line' },
{ value: 'issue.root.stopline', label: 'Stop Line' },
{ value: 'issue.root.startcolumn', label: 'Start Column' },
{ value: 'issue.root.stopcolumn', label: 'Stop Column' },
{ value: 'issue.root.issuename', label: 'Issue Name' },
{ value: 'issue.root.issuecategory', label: 'Issue Category' },
{ value: 'issue._', label: 'Issue Description' },
];
const sampleData = [
{
root: {
filename:
'/home/users/john-doe/workspace/foo-project/src/main/classes/foo.cls',
},
issue: {
root: {
priority: 1,
url: 'www.example.com',
startline: 100,
stopline: 105,
startcolumn: 20,
stopcolumn: 25,
issuename: 'blah',
issuecategory: 'Category A',
},
_: ' Fox ',
},
},
];
const json2csvOptions = {
fields: json2csvFields,
quote: '',
header: true,
transforms: [
(item) => ({
'root.filename': item.root.filename.replace(
'/home/users/john-doe/workspace/foo-project/src/main/classes/',
''
),
'issue._': `"${item.issue._.trim()}"`,
// Except for the above two, everything else doens't need any transformation.
'issue.root.priority': item.issue.root.priority,
'issue.root.url': item.issue.root.url,
'issue.root.startline': item.issue.root.startline,
'issue.root.stopline': item.issue.root.stopline,
'issue.root.startcolumn': item.issue.root.startcolumn,
'issue.root.stopcolumn': item.issue.root.stopcolumn,
'issue.root.issuename': item.issue.root.issuename,
'issue.root.issuecategory': item.issue.root.issuecategory,
}),
],
};
const json2csvParser = new Json2csvParser(json2csvOptions);
const csv = json2csvParser.parse(sampleData);
console.log(csv);
This prints below output:
File Name,Priority,URL,Start Line,Stop Line,Start Column,Stop Column,Issue Name,Issue Category,Issue Description
foo.cls,1,www.example.com,100,105,20,25,blah,Category A,"Fox"
EDIT: Updated code to a working example.
After listing the two properties with special treatment, use Object.fromEntries and Object.entries to transform all the issue.root properties to their flat structure with .s in the property names. Then that object can be spread into the returned object.
const transformsFn = ({ root, issue }) => ({
'root.filename': root.filename.replace(
'/home/users/john-doe/workspace/foo-project/src/main/classes/',
''
),
'issue._': `"${issue._.trim()}"`,
...Object.fromEntries(
Object.entries(issue.root).map(
([key, val]) => [`issue.root.${key}`, val]
)
),
});
const json2csvOptions = {
fields: json2csvFields,
quote: '',
header: true,
transforms: [transformsFn],
};
Given is a data-structure as follows ...
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
}, {
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: [],
}],
};
... but object properties might change in value and vary by name (key) and count (amount of entries).
What's stable though, is the base data-structure with an object's/item's full property (string value) and the possible presence of a children property (array type, empty of not).
In order to later change a data-item's value one needs to first find/retrieve the former from the nested data-structure by e.g. an item's known full property value.
In case of an item like ...
{
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: [],
}
... where one wants to change e.g. children, the item first needs to be found/retrieved via its known full property value of "/home/adityam/Documents/anotherFolder".
How would one achieve such a task?
Searching for the node
Recursion!
You can find a reference for such a tree node with a recursive (search) function:
All recursive algorithms must obey three important laws:
A recursive algorithm must call itself, recursively.
A recursive algorithm must have a base case.
A recursive algorithm must change its state and move toward the base case.
For example findNodeRecursive(name, node):
If property full of node equals name, return node. (Base case: Found)
If property type of node is not "dir", return null. (Base case: Cannot be inside)
For each element childNode of property children of node: (Moving toward some base case)
Let result be the result of the call findNodeRecursive(name, childNode). (Recursive call)
If result is not null, return result. (Base case: Found in children)
Return null. (Base case: Not found)
// Implementation of the algorithm above
function findNodeRecursive(fullName, node) {
if (node.full === fullName) return node;
if (node.type !== "dir") return null;
for (const childNode of node.children) {
const result = findNodeRecursive(fullName, childNode);
if (result !== null) return result;
}
return null;
}
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [
{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
},
{
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: []
}
]
};
console.log(findNodeRecursive("/home/adityam/Documents/anotherFolder", tree));
Iteratively
There is also an iterative solution, which requires flattening the tree to a flat array, and then search for the node by its name.
Flattening can be done in multiple ways, either recursively again, or iteratively.
function findNodeIterative(name, node) {
const nodes = [node];
// Iterative flattening
for (let i = 0; i < nodes.length; ++i) {
if (nodes[i].children) nodes.push(...nodes[i].children);
}
return nodes.find(n => n.full === name);
}
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [
{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
},
{
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: []
}
]
};
console.log(findNodeIterative("/home/adityam/Documents/anotherFolder", tree));
Modifying children
The value of children is an array. If you want to modify this array, you can use one of its mutating methods, for example Array.splice().
// Reference found with some function, for example the above findByName()
const node = {
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: []
};
const nodesToAdd = [
{
name: "someFile.txt",
type: "file",
full: "/home/adityam/Documents/anotherFolder/someFile.txt"
},
{
name: "someFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder/someFolder",
children: []
}
];
console.log("Before modifying:\nNode:", node);
node.children.splice(0, 0, ...nodesToAdd);
console.log("After modifying:\nNode:", node);
.as-console-wrapper{max-height:unset!important;top:0}
As others have already answered, I will post the answer that I wrote earlier, but would usually not post until the OP showed an attempt.
I think we're best off breaking apart the tree navigation code from the code that checks if we're at the right node and from the code that modifies a node.
Since I don't know what sort of modification you are interested in performing, I just add a notice property to the object, but you can use any function that returns a new version of the object, whether an altered clone, a reference to a mutated original, or something else entirely. Here's an example:
const modifyNode = (pred, fn) => (node, _, __,
{children = [], ...rest} = node,
kids = children .map (modifyNode (pred, fn))
) => pred (node)
? fn (node)
: {...rest, ...(kids .length ? {children: kids} : {})}
const modifyByPath = (path) => modifyNode (
(node) => node.full === path,
(node) => ({...node, notice: '*** this was modified ***'})
)
var tree = {name: "Documents", type: "dir", full: "/home/adityam/Documents", children: [{name: "file.txt", type: "file", full: "/home/adityam/Documents/file.txt", }, {name: "anotherFolder", type: "dir",full: "/home/adityam/Documents/anotherFolder", children: [/* ... */]}]}
console .log (modifyByPath ('/home/adityam/Documents/anotherFolder') (tree))
.as-console-wrapper {max-height: 100% !important; top: 0}
We have a utility function modifyNode that accepts a predicate function to test whether we've hit the right node and a modification function that takes a node and returns a node, replaced or altered as desired. It returns a function that takes a node recursively configured with children arrays of objects (themselves with the same structure) and returns an altered version of your tree with every matching node replaced with the result of calling your modification function.
Our main function, modifyByPath, accepts a full path name and calls modifyNode with a simple test predicate and a dummy modification function, which returns a function that does our main work. We will call it like modifyByPath (path) (tree).
The OP's actual use case seems to be finding an array's data-item within a nested data-structure of unknown depth of the form ...
{
/* data-item or root-object/node */
additionalKey: "value-pair(s)",
children: [{
/* data-item */
additionalKey: "value-pair(s)",
children: [
/* optional and possibly empty `children` array */
],
}],
}
... in order to later manipulate the returned matching sub-data-structure. The current use case is to find such an item based on any item's unique key-value pair of the full property.
Though this can be done very easily with a recursive approach, the hereby provided generic implementation allows searching by a to be passed configuration which allows custom values for a data-structure's child-array name (here ... { arrKey: 'children' }) and of a props property which either partially or fully covers a to be matched item's properties/entries signature (here, e.g. ... { full: '/home/adityam/Documents/file.txt' } or even { name: 'Documents', type: 'dir' } ).
The find function itself is implemented in a way that it accepts any type as 1st argument and the finder configuration as its 2nd. If the first argument was an array-type then its find method is going to execute the implemented find function self-recursively. For any other object type (except the null value) an if clause iterates over the provided props' entries in order to assure that every of the props' key-value pairs has a matching counterpart in the passed and currently processed type (the function's first passed argument). In case the current sub-data-item's type does not match, another self recursion takes place; this time with a possible present child array which gets accessed via the currently processed type and the configuration's arrKey value.
As soon as a match got found the configuration which is passed with every recursion gets assigned the matching sub-structure's reference as finder.match. The latter also serves as the recursive find function's only return value which also makes sure that an array's find process will exit early.
function recursivelyFindArrayItemByProperties(type, finder) {
const { arrKey, props } = finder;
if (Array.isArray(type)) {
type
// find will exit early.
.find(item =>
!!recursivelyFindArrayItemByProperties(item, finder)
);
} else if (type && ('object' === typeof type)) {
if (
Object
.entries(props)
.every(([key, value]) => type[key] === value)
) {
finder.match = type;
} else {
recursivelyFindArrayItemByProperties(type[arrKey], finder);
}
}
return finder.match;
}
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
}, {
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: [{
name: "fooBar.txt",
type: "file",
full: "/home/adityam/Documents/fooBar.txt",
}, {
name: "bazBiz.txt",
type: "file",
full: "/home/adityam/Documents/bazBiz.txt",
}],
}],
};
console.log(
'found by ... { full: "/home/adityam/Documents/fooBar.txt" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/fooBar.txt",
},
})
);
console.log(
'found by ... { full: "/home/adityam/Documents/bazBiz.txt" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/bazBiz.txt",
},
})
);
console.log(
'\nfound by ... { full: "/home/adityam/Documents/file.txt" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/file.txt",
},
})
);
console.log(
'\nfound by ... { full: "/home/adityam/Documents/anotherFolder" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/anotherFolder",
},
})
);
console.log(
'found by ... { full: "/home/adityam/Documents" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents",
},
})
);
console.log(
'\nfound by ... { name: "anotherFolder", type: "dir" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
name: "anotherFolder",
type: "dir",
// full: "/home/adityam/Documents/anotherFolder",
},
})
);
console.log(
'found by ... { name: "Documents", type: "dir" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
name: "Documents",
type: "dir",
// full: "/home/adityam/Documents",
},
})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Knowing all this, one of cause now could refactor the current find implementation which returns a single, namely the very first matching sub-structure's, reference into a match solution which recursively collects any matching sub-structure's reference.
function recursivelyMatchArrayItemsByProperties(type, finder) {
const { arrKey, props } = finder;
if (Array.isArray(type)) {
type
.filter(item =>
!!recursivelyMatchArrayItemsByProperties(item, finder)
);
} else if (type && ('object' === typeof type)) {
if (
Object
.entries(props)
.every(([key, value]) => type[key] === value)
) {
(finder.matches ??= []).push(type);
} else {
recursivelyMatchArrayItemsByProperties(type[arrKey], finder);
}
}
return finder.matches;
}
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
}, {
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: [{
name: "fooBar.txt",
type: "file",
full: "/home/adityam/Documents/fooBar.txt",
}, {
name: "bazBiz.txt",
type: "file",
full: "/home/adityam/Documents/bazBiz.txt",
}],
}],
};
console.log(
'matches by ... { full: "/home/adityam/Documents/fooBar.txt" } ... ',
recursivelyMatchArrayItemsByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/fooBar.txt",
},
})
);
console.log(
'matches by ... { type: "file" } ... ',
recursivelyMatchArrayItemsByProperties(tree, {
arrKey: 'children',
props: {
type: "file",
},
})
);
console.log(
'matches by ... { type: "dir" } ... ',
recursivelyMatchArrayItemsByProperties(tree, {
arrKey: 'children',
props: {
type: "dir",
},
})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
I am dynamically adding and removing Dropdowns based on the index of the array. I am setting the index using. When adding or removing a dropdown, I increment and decrement that index. The goal would be an array that looks something like this:
[
{ index: 0, type: "facebook" },
{ index: 1, type: "instagram" }
]
The problem is when I add a new dropdown, the index is incrementing by 2 or 3 instead of 1, resulting in the following output.
[
{ index: 0, type: "facebook" },
{ index: 2, type: "instagram" }
]
Here is the code for my component:
class SocialProfileComponent extends Component {
constructor(props) {
super(props);
let index = 0;
this.state = {
options: [
{value: 'email', label: 'Email'},
{value: 'instagram', label: 'Instagram'},
{value: 'linkedin', label: 'Linkedin'},
{value: 'pinterest', label: 'Pinterest'},
{value: 'skype', label: 'Skype'},
{value: 'tiktok', label: 'TikTok'},
{value: 'tumblr', label: 'Tumblr'},
{value: 'twitter', label: 'Twitter'},
{value: 'whatsapp', label: 'WhatsApp'},
{value: 'wordpress', label: 'Wordpress'},
{value: 'youtube', label: 'Youtube'},
{value: 'other', label: 'Other'},
],
socialDetails: [
{
index: index,
type: "",
link: "",
}
]
};
}
addNewRow = (e) => {
this.setState(prevState => ({
socialDetails: [
...prevState.socialDetails,
{
index: index++,
type: "",
link: "",
}
]
}));
}
deleteRow = (index) => {
this.setState({
socialDetails: this.state.socialDetails.filter(
(s) => index !== s.index
)
})
}
clickOnDelete(record) {
this.setState({
socialDetails: this.state.socialDetails.filter(r => r!==record)
})
}
componentDidMount() {
}
render = () => {
let {socialDetails, options} = this.state;
const {onInputChange} = this.props;
return (
<>
<SocialProfile
label={`Social profiles`}
addRow={this.addNewRow}
deleteRow={this.deleteRow}
socialDetails={socialDetails}
options={options}
onInputChange={onInputChange}
formKey={'socialprofiles'}
createKeyValue={this.createNewKeyValuePair}
placeholder={'Select'}
/>
</>
)
}
}
Code Sandbox
The behavior you are experiencing where the index increases by 2 or 3 is a result of React strict mode. In addition to other things, strict mode helps detect unexpected side effects to help you prepare your app for the upcoming concurrent mode feature. In concurrent mode, React will break up rendering into smaller chunks pausing and resuming work as necessary. This means that render phase lifecycle methods can be run more than once.
To help you prepare for this upcoming behavior of concurrent mode, strict mode will intentionally invoke render phase lifecycles twice to identify potential side effects. State updater functions are one instance of this, meaning that calling index++ in your state updater function will be run twice in strict mode.
The easiest solution would be to simply assign the new index to a variable before calling this.setState so that your state updater function is idempotent and can be called more than once.
addNewRow = (e) => {
const newIndex = ++this.index
this.setState((prevState) => ({
socialDetails: [
...prevState.socialDetails,
{
index: newIndex,
type: "",
link: ""
}
]
}));
};
I have somewhat complex set of data that I would need to simplify and split into two different sets, based on a comparison on nested object property value.
Here's the data structure I'm working with:
[
{
object: { id: 123 },
group: [
{
events: [
{
type: 'type',
schedule: [
{
time: '2019-10-30T09:30:00+00:00',
},
{
time: '2019-10-21T21:00:00+00:00',
}
],
},
{
type: 'type',
schedule: [
{
time: '2019-10-24T09:30:00+00:00',
},
{
time: '2019-09-22T21:00:00+00:00',
},
],
},
],
},
],
},
]
Most important thing would be to split this data into two different sets (arrays of objects), based on whatever or not the schedule value of time is in the past or in the future. It would also help to simplify the structure as a whole. There is a lot of properties attached to the objects and I'm fine brining in the whole object instead of just cherry-picking the important ones, as long as the nesting is logical and usable.
So something like this for the "past" data would be ideal:
[
{
id: 123,
events: [
{
type: 'type',
schedule: [
{
time: '2019-10-21T21:00:00+00:00',
}
],
},
{
type: 'type',
schedule: [
{
time: '2019-09-22T21:00:00+00:00',
}
],
}
]
}
]
I've been trying to use the different array methods (filter and map) to spit out something suitable for my needs, but can't figure out how to do it right. Mostly how to filter based on a nested value and copy over all the nesting structure on a match.
You'll need map() to restructure your array, spread syntax to iterate over object properties in-place, and filter() to filter the data based on a condition.
Using the code below, you can get an array of all past events. You can modify the condition accordingly to get all future events.
// mapping from old data array
const pastData = data.map(({object, group}) => ({
// get all properties of the nested "object"
...object,
// map "events" into a new structure
events: group[0].events.map((event) => (
{
// get all other properties
...event,
// include only those "schedule" objects where time is less than current date
schedule: event.schedule.filter(schedule => new Date(schedule.time) < new Date()),
}
)),
}));
Here's a working example:
const data = [
{
object: { id: 123 },
group: [
{
events: [
{
type: 'type',
schedule: [
{
time: '2019-10-30T09:30:00+00:00',
},
{
time: '2020-10-21T21:00:00+00:00',
}
],
},
{
type: 'type',
schedule: [
{
time: '2019-10-24T09:30:00+00:00',
},
{
time: '2020-09-22T21:00:00+00:00',
},
],
},
],
},
],
},
];
const pastData = data.map(({object, group}) => ({
...object,
events: group[0].events.map((event) => (
{
...event,
schedule: event.schedule.filter(schedule => new Date(schedule.time) < new Date()),
}
)),
}));
const futureData = data.map(({object, group}) => ({
...object,
events: group[0].events.map((event) => (
{
...event,
schedule: event.schedule.filter(schedule => new Date(schedule.time) >= new Date())
}
))
}));
console.log('past data:', pastData, ', future data:', futureData);
Try to use map method and spread operator:
const result = data.map(({object, group}) =>
({ ...object, events: group.map(g=> g.events)}));
const data =
[
{
object: { id: 123 },
group: [
{
events: [
{
type: 'type',
schedule: [
{
time: '2019-10-30T09:30:00+00:00',
},
{
time: '2019-10-21T21:00:00+00:00',
}
],
},
{
type: 'type',
schedule: [
{
time: '2019-10-24T09:30:00+00:00',
},
{
time: '2019-09-22T21:00:00+00:00',
},
],
},
],
},
],
},
];
const result = data.map(({object, group}) => ({ ...object, events: group.map(g=> g.events)}));
console.log(result)