Thamaraiselvam
Thamaraiselvam

Reputation: 7080

how to group by nested properties using lodash?

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);

Upvotes: 4

Views: 7873

Answers (3)

Koushik Chatterjee
Koushik Chatterjee

Reputation: 4175

Hopefully, this is what you are looking for.

  1. First group it by employee_.id
  2. Then map each group, take employee of first one (since every group must have one entry)
  3. 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>

Upvotes: 3

Ori Drori
Ori Drori

Reputation: 193358

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>

Upvotes: 2

jo_va
jo_va

Reputation: 13993

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);

Upvotes: 1

Related Questions