如何使用 lodash 按嵌套属性分组?

Posted

技术标签:

【中文标题】如何使用 lodash 按嵌套属性分组?【英文标题】:how to group by nested properties using lodash? 【发布时间】:2019-07-29 06:43:26 【问题描述】:

我有一个对象数组


    "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
        
    ]

我需要将它们转换成

[
    "_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
    ]
]

我已经通过部分使用 lodash 和 vanilla js 完成了它,它完全可以正常工作。但可读性完全不好。我想单独使用 lodash 来实现这一点。有什么帮助吗?

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

【问题讨论】:

【参考方案1】:

希望这就是您正在寻找的。​​p>

    首先按employee_.id分组 然后映射每个组,获取第一个员工(因为每个组 必须有一个条目) 然后将每个组的所有其他成员(并取出外部部分)映射到work (除员工对象之外的所有内容)

下面是一个例子:

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>

【讨论】:

【参考方案2】:

您可以创建一个使用 lodash 的 _.flow() 按员工 ID 分组的函数,然后使用工作数组创建一个员工对象:

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>

【讨论】:

完美+1,谢谢 @OriDrori 尽量避免使用omit,而是将其余属性设为employee, ...rest 并使用rest【参考方案3】:

您可以使用带有 Object.values()Array.reduce() 和解构分配的纯 javascript 简洁地做到这一点:

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

【讨论】:

谢谢 +1 整洁,但我正在寻找 lodash 的答案,无论如何我会接受你的答案,如果我找不到任何与 lodash 相关的内容。 @Thamaraiselvam 不明白您为什么接受答案的 loadash 版本(我的和 Ori Drori 的答案)然后不接受。这个使用普通 JS 的答案看起来不错,然后你要求 lodash versoin(在这个 ans 的最后一条评论中),之后我想出了一些 lodash 解决方案(认为这可能对你有帮助)。不知道你到底在找什么。 @KoushikChatterjee 您在发布最佳答案方面做得非常出色。由于我使用的是 typescript ,因此您的答案存在一些语法问题,我很着急,所以我使用了 jo_va 答案。 @Thamaraiselvam 嗯,实际上这与我的答案或任何人的答案无关,如果您有任何问题,请评论您应该在那里评论的任何答案,以便为所有 SO 用户提供更大的图景可能会遇到这种问题。

以上是关于如何使用 lodash 按嵌套属性分组?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Postgresql中按嵌套数组的重复值分组?

按属性值排序对象

嵌套熊猫数据框 - 如何按数据选择/分组?

如何按 ReactJS 材料表中嵌套对象中的值分组?

Django模板:如何通过每个字典的嵌套属性重新组合字典列表?

使用 Lodash 按属性合并对象数组