I have the following objects
Person {
name: string
birthday: Date
lifeEvents: LifeEvent[]
}
LifeEvent {
eventId: number
message: string
comments: string
}
As the data comes in chunks, I will have an array of Person
with one object that has name
and birthday
with values but lifeEvents
is empty (Think of this one like a parent object.)
All other objects won't have birthday and name populated and will have only one LifeEvent
with either eventId
and message
with values or eventId
and comments
Within that array, I need to get the parent object, which has name and birthday with values, then get all lifeEvents from the remaining objects, merge all items that contains same eventId into a LifeEvent
then push it to lifeEvents of the parent.
I have tried array.reduce, array.map but can't figure out a way of combining those objects into one.
My output should be only one Person
with all lifeEvents
merged by eventId
Sample data:
let results = [
{
name: 'Test1',
birthday: '2022-06-14',
lifeEvents: null
},
{
name: null,
birthday: null,
lifeEvents: [
{
eventId: 1,
message: 'First event',
comments: null
}
]
},
{
name: null,
birthday: null,
lifeEvents: [
{
eventId: 2,
message: 'Second event',
comments: null
}
]
},
{
name: null
birthday: null
lifeEvents: [
{
eventId: 1,
message: null,
comments: 'First event comment'
}
]
},
{
name: null
birthday: null
lifeEvents: [
{
eventId: 2,
message: null,
comments: 'Second event comment'
}
]
},
]
Appreciate any help.
CodePudding user response:
The following produces the requested result based on examples provided:
let results = [
{
name: 'Test1',
birthday: '2022-06-14',
lifeEvents: null
},
{
name: null,
birthday: null,
lifeEvents: [
{
eventId: 1,
message: 'First event',
comments: null
}
]
},
{
name: null,
birthday: null,
lifeEvents: [
{
eventId: 2,
message: 'Second event',
comments: null
}
]
},
{
name: null,
birthday: null,
lifeEvents: [
{
eventId: 1,
message: null,
comments: 'First event comment'
}
]
},
{
name: null,
birthday: null,
lifeEvents: [
{
eventId: 2,
message: null,
comments: 'Second event comment'
}
]
},
];
// extract parent
const parentResult = results.find((result) => result.name);
// generate unique events from sibling entities
const uniqueEvents = new Map();
results.forEach((result) => result.lifeEvents?.forEach(
(lifeEvent) => {
if (uniqueEvents.has(lifeEvent.eventId)) {
updateEvent(lifeEvent);
} else {
uniqueEvents.set(lifeEvent.eventId, { eventId: lifeEvent.eventId, message: lifeEvent.message, comments: lifeEvent.comments});
}
})
);
// function to update event that is already stored in uniqueEvents
function updateEvent(lifeEvent) {
const existingLifeEvent = uniqueEvents.get(lifeEvent.eventId);
if (lifeEvent.message) existingLifeEvent.message = lifeEvent.message;
if (lifeEvent.comments) {
if (existingLifeEvent.comments) {
existingLifeEvent.comments.concat(lifeEvent.comments)
} else {
existingLifeEvent.comments = lifeEvent.comments;
}
}
}
// populate lifeEvents inside the parentResult
parentResult.lifeEvents = [];
uniqueEvents.forEach((uniqueId) => {
parentResult.lifeEvents.push(uniqueId);
});
console.log(parentResult);
CodePudding user response:
Premise: The data structure you are using is wrong, you should try to use arrays with homogenous models.
That said I used a reduce method, with a condition to treat the first element in a different way from the other ones.
Last thing, you said merge lifeEvents, I assume you meant to overwrite the nullish values for events with same ids, if you want to overwrite all values then you can omit the merge utility function I wrote.
let results = [{
name: 'Test1',
birthday: '2022-06-14',
lifeEvents: null,
},
{
name: null,
birthday: null,
lifeEvents: [{
eventId: 1,
message: 'First event',
comments: null,
}, ],
},
{
name: null,
birthday: null,
lifeEvents: [{
eventId: 2,
message: 'Second event',
comments: null,
}, ],
},
{
name: null,
birthday: null,
lifeEvents: [{
eventId: 1,
message: null,
comments: 'First event comment',
}, ],
},
{
name: null,
birthday: null,
lifeEvents: [{
eventId: 2,
message: null,
comments: 'Second event comment',
}, ],
},
];
const merge = (o1, o2) => {
const r = {...o1}
Object.keys(o1).forEach(k => r[k] = o2[k] || o1[k])
return r
}
const r = results.reduce((o, curr, i) => {
if (i === 0) {
return { ...o,
lifeEvents: []
};
} else {
const currentEvent = curr.lifeEvents[0]
const idx = o.lifeEvents.findIndex((_o) => _o.eventId === currentEvent.eventId);
if (idx !== -1) return { ...o,
lifeEvents: o.lifeEvents.map((_o, i) => i === idx ? merge(_o, currentEvent) : _o)
}
else return { ...o,
lifeEvents: [...o.lifeEvents, currentEvent]
}
}
}, results[0]);
console.log("RESULT:", r);