JS Reduce 和 group JSON by deeply nested object

JS Reduce and group JSON by deeply nested object

我正在通过 REST 拉取一个 JSON 对象数组,其中包含一些字段和一些嵌套对象。

我要创建的是一个来自具有以下结构的嵌套 JSON 对象数组的分组摘要对象:

 var data = [
        {
            "Id": 79,
            "Date": "2019-02-17T00:00:00-07:00",
            "StartTime": 1535385600,
            "EndTime": 1535416200,
            "Slots": [
                {
                    "blnEmptySlot": false,
                    "strType": "B",
                    "intStart": 3600,
                    "intEnd": 5400,
                    "intUnixStart": 1535389200,
                    "intUnixEnd": 1535391000,
                }
            ],
            "OperationalUnit": 3,
            "Created": "2019-01-31T11:23:29+02:00",
            "StartTimeLocalized": "2019-02-17T10:00:00+02:00",
            "EndTimeLocalized": "2019-02-17T19:00:00+02:00",
            "_MetaData": {
                "AttendeeInfo": {
                    "Id": 111,
                    "AttendeeDisplayName": "att_name1",
                    "AttendeeProfile": 406,
                    "Attendee": 406,
                    "Photo": "avatar_path"
                  },
                "OperationalUnitInfo": {
                    "Id": 3,
                    "OperationalUnitName": "op_unit_name",
                    "Company": 1,
                    "CompanyName": "comp_name",
                    "LabelWithCompany": "comp_label"
                },
            }
        },
        {
            "Id": 80,
            "Date": "2019-02-17T00:00:00-07:00",
            "StartTime": 1535385600,
            "EndTime": 1535416200,
            "Slots": [
                {
                    "blnEmptySlot": false,
                    "strType": "B",
                    "intStart": 3600,
                    "intEnd": 5400,
                    "intUnixStart": 1535389200,
                    "intUnixEnd": 1535391000,
                }
            ],
            "OperationalUnit": 3,
            "Created": "2019-01-31T11:23:29+02:00",
            "StartTimeLocalized": "2019-02-17T10:00:00+02:00",
            "EndTimeLocalized": "2019-02-17T19:00:00+02:00",
            "_MetaData": {
                "AttendeeInfo": {
                    "Id": 112,
                    "AttendeeDisplayName": "att_name2",
                    "AttendeeProfile": 407,
                    "Attendee": 407,
                    "Photo": "avatar_path"
                  },
                "OperationalUnitInfo": {
                    "Id": 3,
                    "OperationalUnitName": "op_unit_name",
                    "Company": 1,
                    "CompanyName": "comp_name",
                    "LabelWithCompany": "comp_label"
                },
            }
        }
    ];

总体目的是创建一个包含开始和结束日期时间的事件对象列表、一个 LabelWithCompany 字符串(深层嵌套对象)和一个按 OperationalUnitName 以及开始和结束时间分组的所有参加者的列表。

示例:

[
    {
        "2019-02-17T00:00:00-08:00": {//Date
            "2019-02-17T10:00:00+02:00": {//StartTimeLocalized
                "2019-02-17T19:00:00+02:00": {//EndTimeLocalized
                    "[NYC] Network - Solutions": {//LabelWithCompany
                        "attendees": [
                            "att_name1",//AttendeeDisplayName
                            "att_name2"  //AttendeeDisplayName    
                        ]
                    }
                }
            }
        }
    }
]

我假设 map 和 reduce 是必要的函数,但我在执行多个嵌套的 reduce 时遇到了麻烦。 关于如何将这些对象聚合成聚合格式的任何其他建议,该格式将包含每个会话的所有与会者。

您可以使用一些辅助函数来获取嵌套对象的值并设置路径并通过获取键数组返回最后一个嵌套对象。

然后您需要将嵌套结果集的键与另一个键一起获取用于推送到结果的值。

const
    getValue = (object, path) => [].concat(path).reduce((o, k) => o[k], object),
    setPath = (object, path) => [].concat(path).reduce((o, k) => o[k] = o[k] || {}, object);

var data = [{ Id: 79, Date: "2018-08-27T00:00:00-07:00", StartTime: 1535385600, EndTime: 1535416200, Slots: [{ blnEmptySlot: false, strType: "B", intStart: 3600, intEnd: 5400, intUnixStart: 1535389200, intUnixEnd: 1535391000 }], OperationalUnit: 3, Created: "2019-01-31T11:23:29+02:00", StartTimeLocalized: "2019-02-17T10:00:00+02:00", EndTimeLocalized: "2019-02-17T19:00:00+02:00", _MetaData: { AttendeeInfo: { Id: 111, AttendeeDisplayName: "att_name1", AttendeeProfile: 406, Attendee: 406, Photo: "avatar_path" }, OperationalUnitInfo: { Id: 3, OperationalUnitName: "op_unit_name", Company: 1, CompanyName: "comp_name", LabelWithCompany: "comp_label" } } }, { Id: 80, Date: "2018-08-27T00:00:00-07:00", StartTime: 1535385600, EndTime: 1535416200, Slots: [{ blnEmptySlot: false, strType: "B", intStart: 3600, intEnd: 5400, intUnixStart: 1535389200, intUnixEnd: 1535391000 }], OperationalUnit: 3, Created: "2019-01-31T11:23:29+02:00", StartTimeLocalized: "2019-02-17T10:00:00+02:00", EndTimeLocalized: "2019-02-17T19:00:00+02:00", _MetaData: { AttendeeInfo: { Id: 112, AttendeeDisplayName: "att_name2", AttendeeProfile: 407, Attendee: 407, Photo: "avatar_path" }, OperationalUnitInfo: { Id: 3, OperationalUnitName: "op_unit_name", Company: 1, CompanyName: "comp_name", LabelWithCompany: "comp_label" } } }],
    keys = ["Date", "StartTimeLocalized", "EndTimeLocalized", ["_MetaData", "OperationalUnitInfo", "LabelWithCompany"]],
    value = ["_MetaData", "AttendeeInfo", "AttendeeDisplayName"],
    result = data.reduce((r, o) => {
        var temp = setPath(r, keys.map(getValue.bind(null, o)));

        temp.attendees = temp.attendees || [];
        temp.attendees.push(getValue(o, value));
        return r;
    }, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

您可以定义一个函数来简化层次结构的创建 (drill),然后遍历记录,如下所示:

const data = [{"Id": 79,"Date": "2019-02-17T00:00:00-07:00","StartTime": 1535385600,"EndTime": 1535416200,"Slots": [{"blnEmptySlot": false,"strType": "B","intStart": 3600,"intEnd": 5400,"intUnixStart": 1535389200,"intUnixEnd": 1535391000,}],"OperationalUnit": 3,"Created": "2019-01-31T11:23:29+02:00","StartTimeLocalized": "2019-02-17T10:00:00+02:00","EndTimeLocalized": "2019-02-17T19:00:00+02:00","_MetaData": {"AttendeeInfo": {"Id": 111,"AttendeeDisplayName": "att_name1","AttendeeProfile": 406,"Attendee": 406,"Photo": "avatar_path"},"OperationalUnitInfo": {"Id": 3,"OperationalUnitName": "op_unit_name","Company": 1,"CompanyName": "comp_name","LabelWithCompany": "comp_label"},}},{"Id": 80,"Date": "2019-02-17T00:00:00-07:00","StartTime": 1535385600,"EndTime": 1535416200,"Slots": [{"blnEmptySlot": false,"strType": "B","intStart": 3600,"intEnd": 5400,"intUnixStart": 1535389200,"intUnixEnd": 1535391000,}],"OperationalUnit": 3,"Created": "2019-01-31T11:23:29+02:00","StartTimeLocalized": "2019-02-17T10:00:00+02:00","EndTimeLocalized": "2019-02-17T19:00:00+02:00","_MetaData": {"AttendeeInfo": {"Id": 112,"AttendeeDisplayName": "att_name2","AttendeeProfile": 407,"Attendee": 407,"Photo": "avatar_path"},"OperationalUnitInfo": {"Id": 3,"OperationalUnitName": "op_unit_name","Company": 1,"CompanyName": "comp_name","LabelWithCompany": "comp_label"},}}];

const drill = (o, key, ...keys) => key ? drill(o[key] = o[key] || {}, ...keys) : o; 

const result = {};    
for (const e of data) {
    const key = drill(result, e.Date, 
                              e.StartTimeLocalized, 
                              e.EndTimeLocalized, 
                              e._MetaData.OperationalUnitInfo.LabelWithCompany);
    key.attendees = (key.attendees || []).concat(
                              e._MetaData.AttendeeInfo.AttendeeDisplayName);
}

console.log(result);

注意:将输出包装在数组中似乎没有用,但您当然可以这样做。