how to group by nested properties using lodash? - javascript

I have array of objects
{
"work": [{
"_id": "5c80c5c00c253823fc443337",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-01-02T18:30:00.000Z",
"employee": {
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
},
"allocation": 30
},
{
"_id": "5c80c5ef0c253823fc443339",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-09-30T18:30:00.000Z",
"employee": {
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
},
"allocation": 100
},
{
"_id": "5c80c60b0c253823fc44333a",
"start": "2018-12-31T18:30:00.000Z",
"end": "2020-10-07T18:30:00.000Z",
"employee": {
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
},
"allocation": 25
},
{
"_id": "5c80c65e0c253823fc44333b",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-10-04T18:30:00.000Z",
"employee": {
"_id": "5c80c1940c253823fc44332b",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
},
"allocation": 50
},
{
"_id": "5c80c7240c253823fc44333f",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-10-09T18:30:00.000Z",
"employee": {
"_id": "5c80c26e0c253823fc44332e",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890"
},
"allocation": 25
}
]
}
I need to convert them into
[{
"_id": "5c80c16e0c253823fc44332a",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890",
"work": [{
"_id": "5c80c5c00c253823fc443337",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-01-02T18:30:00.000Z",
"allocation": 30
}, {
"_id": "5c80c5ef0c253823fc443339",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-09-30T18:30:00.000Z",
"allocation": 100
}, {
"_id": "5c80c60b0c253823fc44333a",
"start": "2018-12-31T18:30:00.000Z",
"end": "2020-10-07T18:30:00.000Z",
"allocation": 25
}]
}, {
"_id": "5c80c1940c253823fc44332b",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890",
"work": [{
"_id": "5c80c65e0c253823fc44333b",
"start": "2019-01-01T18:30:00.000Z",
"end": "2019-10-04T18:30:00.000Z",
"allocation": 50
}]
}, {
"_id": "5c80c26e0c253823fc44332e",
"status": "active",
"location": "Chennai",
"contact_number": "1234567890",
"work": [{
"_id": "5c80c7240c253823fc44333f",
"start": "2018-12-31T18:30:00.000Z",
"end": "2019-10-09T18:30:00.000Z",
"allocation": 25
}]
}]
I have done it by partially using lodash and vanilla js and it works completely fine. but readability wise is completely bad. I want to achieve this using just lodash alone. Any help?
let ids: any = groupBy(this.project.work, function (res) {
return res.employee._id;
});
for (let id in ids) {
let tmp = [];
let employee_added = false;
ids[id].map((work) => {
if (!employee_added) {
tmp = work.employee;
tmp['work'] = [];
employee_added = true;
}
delete work.employee;
tmp['work'].push(work);
})
this.employees.push(tmp);
}
console.log(this.employees);

Hopefully, this is what you are looking for.
First group it by employee_.id
Then map each group, take employee of first one (since every group
must have one entry)
Then map all other members (and take outer part) of each group to work
(everything apart from employee object)
Here is the example below:
let works = [{"_id":"5c80c5c00c253823fc443337","start":"2019-01-01T18:30:00.000Z","end":"2019-01-02T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":30},{"_id":"5c80c5ef0c253823fc443339","start":"2018-12-31T18:30:00.000Z","end":"2019-09-30T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":100},{"_id":"5c80c60b0c253823fc44333a","start":"2018-12-31T18:30:00.000Z","end":"2020-10-07T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":25},{"_id":"5c80c65e0c253823fc44333b","start":"2019-01-01T18:30:00.000Z","end":"2019-10-04T18:30:00.000Z","employee":{"_id":"5c80c1940c253823fc44332b","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":50},{"_id":"5c80c7240c253823fc44333f","start":"2018-12-31T18:30:00.000Z","end":"2019-10-09T18:30:00.000Z","employee":{"_id":"5c80c26e0c253823fc44332e","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":25}]
let res = _(works)
.groupBy('employee._id')
.map(g => ({...g[0].employee, work: _.map(g, ({employee, ...rest}) => ({...rest}))}))
.value();
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

You can create a function that uses lodash's _.flow() that groups by the employee id, and then creates an employee object with work array:
const { flow, partialRight: pr, groupBy, map, head, get, omit } = _
const fn = flow(
pr(groupBy, 'employee._id'),
pr(map, group => ({ // create the employee objects
...get(head(group), 'employee'), // get the employee data and spread it
work: group.map(o => omit(o, 'employee')) // create the work array by removing the employee from each work object
}))
)
const data = {"work":[{"_id":"5c80c5c00c253823fc443337","start":"2019-01-01T18:30:00.000Z","end":"2019-01-02T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":30},{"_id":"5c80c5ef0c253823fc443339","start":"2018-12-31T18:30:00.000Z","end":"2019-09-30T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":100},{"_id":"5c80c60b0c253823fc44333a","start":"2018-12-31T18:30:00.000Z","end":"2020-10-07T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":25},{"_id":"5c80c65e0c253823fc44333b","start":"2019-01-01T18:30:00.000Z","end":"2019-10-04T18:30:00.000Z","employee":{"_id":"5c80c1940c253823fc44332b","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":50},{"_id":"5c80c7240c253823fc44333f","start":"2018-12-31T18:30:00.000Z","end":"2019-10-09T18:30:00.000Z","employee":{"_id":"5c80c26e0c253823fc44332e","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":25}]}
const result = fn(data.work)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

You can do it succinctly using plain JavaScript with Object.values(), Array.reduce() and desctructuring assignment:
const data = {"work":[{"_id":"5c80c5c00c253823fc443337","start":"2019-01-01T18:30:00.000Z","end":"2019-01-02T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":30},{"_id":"5c80c5ef0c253823fc443339","start":"2018-12-31T18:30:00.000Z","end":"2019-09-30T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":100},{"_id":"5c80c60b0c253823fc44333a","start":"2018-12-31T18:30:00.000Z","end":"2020-10-07T18:30:00.000Z","employee":{"_id":"5c80c16e0c253823fc44332a","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":25},{"_id":"5c80c65e0c253823fc44333b","start":"2019-01-01T18:30:00.000Z","end":"2019-10-04T18:30:00.000Z","employee":{"_id":"5c80c1940c253823fc44332b","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":50},{"_id":"5c80c7240c253823fc44333f","start":"2018-12-31T18:30:00.000Z","end":"2019-10-09T18:30:00.000Z","employee":{"_id":"5c80c26e0c253823fc44332e","status":"active","location":"Chennai","contact_number":"1234567890"},"allocation":25}]};
const result = Object.values(data.work.reduce((acc, work) => {
const { employee: { _id, ...rest }, ...job } = work;
const jobs = (acc[_id] || {}).work || [];
acc[_id] = { _id, ...rest, work: [...jobs, job] };
return acc;
}, {}));
console.log(result);

Related

Transform array of data into grouped data for SectionList component

I'll freely admit that Javascript is not my strongest language, and React Native is very new, so, there may be an obviously easy way to do this that I'm not seeing.
I've got an API that presents some transaction data in a simple structure:
[
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
},
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
},
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
]
I want to present this data using a SectionList component, with the transactions in sections by date. My (likely crude) attempt to solve this was going to be to transform this data into the following structure:
[
{
"date": "2021-09-10",
"transactions": [
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
}
]
},
{
"date": "2021-09-09",
"transactions": [
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
}
]
},
{
"date": "2021-09-07",
"transactions": [
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
]
}
]
But I'm honestly lost as to how to transform this data (or if there's a better way to solve this problem). I started by using Lodash's groupBy function, which seemed promising, but it looks like SectionList doesn't want an object, it wants an array.
Transforming the output of groupBy into an array straight off drops the keys and I've got grouped data but no clear value for the section header.
Again, there's probably some deviously simple way to address this, data comes in as a flat array all the time. I appreciate any guidance, assistance, or examples anybody can point me to.
const input = [
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
},
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
},
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
]
const result = input.reduce((accum, current)=> {
let dateGroup = accum.find(x => x.date === current.date);
if(!dateGroup) {
dateGroup = { date: current.date, transactions: [] }
accum.push(dateGroup);
}
dateGroup.transactions.push(current);
return accum;
}, []);
console.log(result)
Given an array, whenever your result is expecting to have same number of elements, use map, but since your result has different number of elements, use reduce as shown above. The idea is by having reduce, loop over each element, see if you can find the element, and push the current element into the list
The lodash groupBy just helps you with group data, you should process grouped data by converting it into your format.
const input = [
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
},
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
},
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
];
const groupedArray = _.groupBy(input, "date");
let result = [];
for (const [key, value] of Object.entries(groupedArray)) {
result.push({
'date': key,
'transactions': value
})
}
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
simply
const data =
[ { id: 1, title: 'Apple Store', date: '2021-09-10', amount: '$100.00' }
, { id: 41, title: 'Zulauf, Walter and Metz', date: '2021-09-10', amount: '$14.00' }
, { id: 9, title: 'Aufderhar PLC', date: '2021-09-09', amount: '$78.00' }
, { id: 10, title: 'Bayer and Sons', date: '2021-09-07', amount: '$67.00' }
]
const res = Object.entries(data.reduce((r,{id,title,date,amount})=>
{
r[date] = r[date] ?? []
r[date].push({id,title,date,amount})
return r
},{})).map(([k,v])=>({date:k,transactions:v}))
console.log( res )
.as-console-wrapper { max-height: 100% !important; top: 0 }
With lodash you can group by the date then map to the required form:
const input = [{"id":1,"title":"Apple Store","date":"2021-09-10","amount":"$100.00"},{"id":41,"title":"Zulauf, Walter and Metz","date":"2021-09-10","amount":"$14.00"},{"id":9,"title":"Aufderhar PLC","date":"2021-09-09","amount":"$78.00"},{"id":10,"title":"Bayer and Sons","date":"2021-09-07","amount":"$67.00"}];
const result = _.map(
_.groupBy(input, 'date'),
(transactions, date) => ({ date, transactions })
)
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
you could use loadash
var result = _(data)
.groupBy(item => item.date)
.map((value, key) => ({date: key, transactions: value}))
.value();

JavaScript Mapping Object To Array

I would like to convert objects in JavaScript, but I'm not really sure of the best way to do it. I don't often code in the language so I don't really know much of the fundamentals- this is the object I get back from an API call in a React project:
{
"api": {
"results": 380,
"fixtures": [
{
"fixture_id": 65,
"league_id": 2,
"league": {
"name": "Premier League",
"country": "England",
"logo": "https://media.api-sports.io/football/leagues/2.png",
"flag": "https://media.api-sports.io/flags/gb.svg"
},
"event_date": "2018-08-10T19:00:00+00:00",
"event_timestamp": 1533927600,
"firstHalfStart": 1533927600,
"secondHalfStart": 1533931200,
"round": "Regular Season - 1",
"status": "Match Finished",
"statusShort": "FT",
"elapsed": 90,
"venue": "Old Trafford (Manchester)",
"referee": null,
"homeTeam": {
"team_id": 33,
"team_name": "Manchester United",
"logo": "https://media.api-sports.io/football/teams/33.png"
},
"awayTeam": {
"team_id": 46,
"team_name": "Leicester",
"logo": "https://media.api-sports.io/football/teams/46.png"
},
"goalsHomeTeam": 2,
"goalsAwayTeam": 1,
"score": {
"halftime": "1-0",
"fulltime": "2-1",
"extratime": null,
"penalty": null
}
}
]
}
}
I would like to convert it to this array (the array holds multiple objects):
[
{
"homeTeam": {
"id": 33,
"name": "Manchester United",
"teamId": 33
},
"awayTeam": {
"id": 46,
"name": "Leicester",
"teamId": 46
},
"outcome": {
"goalsScoredByAwayTeam": 2,
"goalsScoredByHomeTeam": 1
},
"resulted": true,
"type": "LEAGUE"
}
]
The teamId and id actually need to lookup another object before the final output.
I'm not sure what the best way to do it is. This is my function so far, trying to make use of optional chaining:
function convertFixturesToArray() {
fixturesStore.getFixtures()?.api?.fixtures?.length ? fixtures.api.fixtures.map(fixture => (
//TRANSFORMATION GOES IN HERE
)) : null;
}
You seem on the right track. It should be something like this (written in a slightly more modern JS)
convertFixturesToArray = () => fixturesStore.getFixtures()?.api?.fixtures?.map?.(fixture => {
//Do whatever check you need here with the fixture object
return {
homeTeam: { ...fixture.homeTeam },
awayTeam: { ...fixture.awayTeam },
outcome: {
goalsScoredByAwayTeam: fixture.goalsAwayTeam,
goalsScoredByHomeTeam: fixture.goalsHomeTeam,
},
type: 'LEAGUE',
resulted: true,
},
}) ?? [];
It looks like you're trying to get certain key/value pairs from your api response. With a mix of map, reduce, and find, you can get the values you're looking for by defining them in an array (i.e. desiredProps).
Of course, adding the "outcome" field and your other hardcoded fields would require a bit more logic on top of this. Boris' answer addresses this problem. I've taken a more flexible approach.
let apiResult = {
"fixtures": [
{
"prop1": "a1",
"prop2": "a2",
"prop3": "a3"
},
{
"prop1": "b1",
"prop2": "b2",
"prop3": "b3"
}
]
}
let desiredProps = ["prop2", "prop3"]
let result = apiResult.fixtures.map(x => {
return Object.keys(x).reduce((acc, curr) => {
if (desiredProps.find(y => y === curr)) {
acc[curr] = x[curr]
}
return acc
}, {})
})
console.log(result)

Javascript remove object from array based on greater date key

I have an array like this -
"formats": [
{
"format": "eBook",
"published": "3/3/2014",
"id": "1234"
},
{
"format": "Paperback",
"published": "19/3/2020",
"id": "123"
},
{
"format": "eBook",
"published": "19/3/2020",
"id": "12345"
}]
and I would like to write a js filter function that should return me based on the latest format.So something like this
"formats": [
{
"format": "Paperback",
"published": "19/3/2020",
"id": "123"
},
{
"format": "eBook",
"published": "19/3/2020",
"id": "12345"
}]
Where object with id 1234 is removed because another object with the same format (eBook) has a greater published date.
I tried using JS's filter function, but somehow I am messing it up.
const formats = [
{
"format": "eBook",
"published": "3/3/2014",
"id": "1234"
},
{
"format": "Paperback",
"published": "27/3/2020",
"id": "123"
},
{
"format": "Paperback",
"published": "19/3/2020",
"id": "123"
},
{
"format": "eBook",
"published": "19/3/2020",
"id": "12345"
}];
function filterFormats(formats){
const toTime = (date) => new Date(date.replace(/(\d+)\/(\d+)\/(\d+)/, "$2/$1/$3")).getTime();
const data = formats.reduce((a, b) => {
if(b.format+'' in a && toTime(a[b.format].published) > toTime(b.published)) return a;
a[b.format] = b;
return a;
}, {});
return Object.values(data);
}
console.log(filterFormats(formats));
Here's my solution:
const formats = [
{
"format": "eBook",
"published": "3/3/2014",
"id": "1234"
},
{
"format": "Paperback",
"published": "19/3/2020",
"id": "123"
},
{
"format": "eBook",
"published": "19/3/2020",
"id": "12345"
}]
const getDateObj = (str) => new Date(str.split('/').map(i => i.length<2 ? `0${i}` : i).reverse().join('-'));
const getFilteredArrayOfLatestEntriesForFormats = (formatsArr) => {
const formatToLatestEntriesMap = formatsArr.reduce((latestFormatEntryMap,obj) => {
const publishedAt = getDateObj(obj.published);
if(!latestFormatEntryMap[obj.format] || latestFormatEntryMap[obj.format].publishedAt<publishedAt){
latestFormatEntryMap[obj.format] = {
...obj,
publishedAt: publishedAt
};
}
return latestFormatEntryMap;
},{})
return Object.keys(formatToLatestEntriesMap).map(format => {
delete formatToLatestEntriesMap[format].publishedAt;
return formatToLatestEntriesMap[format];
})
}
console.log(getFilteredArrayOfLatestEntriesForFormats(formats));

how to remove this object from array inside of object in array?

I am not sure how to form this question, but I will do my best.
I don't know how to remove object by _id from 'list:' part.
So, I have one array, and inside of that array I have list of objects,inside of these objects I have again array with objects, so I want to remove one object from that last array, how I can do that?
Cannot fix it for 2 days, I'm stucked!
Thanks!
[
{
"_id": "599a1344bf50847b0972a465",
"title": "British Virgin Islands BC",
"list": [],
"price": "1350"
},
{
"_id": "599a1322bf50847b0972a38e",
"title": "USA (Nevada) LLC",
"list": [
{
"_id": "599a1322bf50847b0972a384",
"title": "Nominee Member",
"service": "nominee-service",
"price": "300"
},
{
"_id": "599a1322bf50847b0972a385",
"title": "Nominee Manager & General Power of Attorney (Apostilled)",
"service": "nominee-service",
"price": "650"
},
{
"_id": "599a1322bf50847b0972a386",
"title": "Special Power of Attorney",
"service": "nominee-service",
"price": "290"
}
],
"price": "789"
},
{
"_id": "599a12fdbf50847b0972a2ad",
"title": "Cyprus LTD",
"list": [
{
"_id": "599a12fdbf50847b0972a2a5",
"title": "Nominee Shareholder",
"service": "nominee-service",
"price": "370"
},
{
"_id": "599a12fdbf50847b0972a2a6",
"title": "Nominee Director & General Power or Attorney (Apostilled)",
"service": "nominee-service",
"price": "720"
},
{
"_id": "599a12fdbf50847b0972a2ab",
"title": "Extra Rubber Stamp",
"service": "other-service",
"price": "40"
}
],
"price": "1290"
}
]
Using Vanilla JS:
function findAndRemove(data, id) {
data.forEach(function(obj) { // Loop through each object in outer array
obj.list = obj.list.filter(function(o) { // Filter out the object with unwanted id, in inner array
return o._id != id;
});
});
}
var data = [{
"_id": "599a1344bf50847b0972a465",
"title": "British Virgin Islands BC",
"list": [],
"price": "1350"
},
{
"_id": "599a1322bf50847b0972a38e",
"title": "USA (Nevada) LLC",
"list": [{
"_id": "599a1322bf50847b0972a384",
"title": "Nominee Member",
"service": "nominee-service",
"price": "300"
},
{
"_id": "599a1322bf50847b0972a385",
"title": "Nominee Manager & General Power of Attorney (Apostilled)",
"service": "nominee-service",
"price": "650"
},
{
"_id": "599a1322bf50847b0972a386",
"title": "Special Power of Attorney",
"service": "nominee-service",
"price": "290"
}
],
"price": "789"
},
{
"_id": "599a12fdbf50847b0972a2ad",
"title": "Cyprus LTD",
"list": [{
"_id": "599a12fdbf50847b0972a2a5",
"title": "Nominee Shareholder",
"service": "nominee-service",
"price": "370"
},
{
"_id": "599a12fdbf50847b0972a2a6",
"title": "Nominee Director & General Power or Attorney (Apostilled)",
"service": "nominee-service",
"price": "720"
},
{
"_id": "599a12fdbf50847b0972a2ab",
"title": "Extra Rubber Stamp",
"service": "other-service",
"price": "40"
}
],
"price": "1290"
}
];
// Empty almost all of list, except middle one
findAndRemove(data, "599a1322bf50847b0972a384");
findAndRemove(data, "599a1322bf50847b0972a386");
findAndRemove(data, "599a12fdbf50847b0972a2a5");
findAndRemove(data, "599a12fdbf50847b0972a2a6");
findAndRemove(data, "599a12fdbf50847b0972a2ab");
console.log(data);
Cleared everything except middle list, just for better visualization.
#Abhijit Kar your one is working perfectly, thanks mate!
How I can later splice this list?
When I was working with objects from first array, I did it like this :
var inventory = jsonArrayList;
for (var i = 0; i < inventory.length; i++) {
if (inventory[i]._id == deleteProductById) {
vm.items.splice(i, 1);
break;
}
}
It would be very helpful, thanks alot!
You can use Array.map and Array.filter to accomplish this. Detailed explanation in comments:
PS: This snippet uses ES6 arrow functions and spread operator
function removeById(arr, id) {
// Array.map iterates over each item in the array,
// and executes the given function on the item.
// It returns an array of all the items returned by the function.
return arr.map(obj => {
// Return the same object, if the list is empty / null / undefined
if (!obj.list || !obj.list.length) return obj;
// Get a new list, skipping the item with the spedified id
const newList = obj.list.filter(val => val._id !== id);
// map function returns the new object with the filtered list
return { ...obj, list: newList };
});
}
const oldArray = <YOUR_ORIGINAL_ARRAY>;
const newArray = removeById(arr, "599a12fdbf50847b0972a2a5");

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