将json对象数组转换为另一个json对象

时间:2017-02-22 20:20:01

标签: javascript json tree

我有一个json对象数组,如下所示。

[
    {
      "wrappedItem": {
        "systemName": "jira",
        "domainObject": "issue",
        "eventType": "creation"
      },
      "id": 39,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "jira",
        "domainObject": "issue",
        "eventType": "predeletion"
      },
      "id": 40,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "jira",
        "domainObject": "issue",
        "eventType": "deletion"
      },
      "id": 41,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "jira",
        "domainObject": "issue",
        "eventType": "update"
      },
      "id": 42,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "jira",
        "domainObject": "recquirement",
        "eventType": "new"
      },
      "id": 43,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "jira",
        "domainObject": "recquirement",
        "eventType": "old"
      },
      "id": 44,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "bitbucket",
        "domainObject": "branch",
        "eventType": "creation"
      },
      "id": 45,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "bitbucket",
        "domainObject": "branch",
        "eventType": "deletion"
      },
      "id": 46,
      "enabled": true
    },
    {
      "wrappedItem": {
        "systemName": "bitbucket",
        "domainObject": "pull-request",
        "eventType": "creation"
      },
      "id": 47,
      "enabled": true
    }
  ]

如果您仔细观察上述数据,可以看到数据可以根据systemName进行分组,然后是domainObject,然后是eventType

我想将数据显示为像时尚一样的树。为此,我决定使用angular-ui-tree第三方库。它期望json对象以某种方式。 (请转到该链接以查看所需的json对象的结构)。

我有一个要求,我必须将我的数据转换为angular-ui-tree所需的结构,以便我可以将我的数据显示为树。

最终,我期待json对象看起来像:

[
  {
    "systemName": "jira",
    "domains": [
      {
        "domainObject": "issue",
        "eventTypes": [
          {
            "eventType": "creation",
            "id": 39,
            "enabled": true
          },
          {
            "eventType": "pre-deletion",
            "id": 40,
            "enabled": true
          },
          {
            "eventType": "deletion",
            "id": 41,
            "enabled": true
          },
          {
            "eventType": "issue",
            "id": 42,
            "enabled": true
          }
        ]
      },
      {
        "domainObject": "requirement",
        "eventTypes": [
          {
            "eventType": "new",
            "id": 43,
            "enabled": true
          },
          {
            "eventType": "old",
            "id": 44,
            "enabled": true
          }
        ]
      }
    ]
  },
  {
    "systemName": "bitbucket",
    "domains": [
      {
        "domainObject": "branch",
        "eventTypes": [
          {
            "eventType": "creation",
            "id": 45,
            "enabled": true
          },
          {
            "eventType": "deletion",
            "id": 46,
            "enabled": true
          }
        ]
      },
      {
        "domainObject": "pull-request",
        "eventTypes": [
          {
            "eventType": "creation",
            "id": 47,
            "enabled": true
          }
        ]
      }
    ]
  }
]  

如您所见,此数据按systemName分组,然后是domainObject,后跟eventType。 有人可以帮我转换上面显示的结构中的数据。

2 个答案:

答案 0 :(得分:2)

您可以使用嵌套哈希表并使用给定键对项目进行分组。

基本上,此提案适用于不同长度的分组属性。在这种情况下,它按

分组
groups = {
    'wrappedItem.systemName': 'domains',
    'wrappedItem.domainObject': 'eventTypes'
}

然后它需要一个用于构建最终对象的函数

{
    eventType: "creation",
    id: 39,
    enabled: true
}

在嵌套分组的末尾

fn = function (o) {
    return { eventType: o.wrappedItem.eventType, id: o.id, enabled: o.enabled };
}

函数getGroupedData需要数据数组,分组对象和回调以生成内部项。

关键功能是一个对象,它为每个级别的组保存一个数组。

一开始,哈希表有一个属性和对结果数组的引用

{
    _: result
}

在数据数组的第一个循环中,通过迭代所有组,它为每个组获得一个新的级别。

首先,它获取第一个组属性的值,即'jira'。它用于检查哈希表中是否存在该属性。实际上不存在'jira',并且使用与原始哈希表相同的模式生成新对象。

{
    _: result
    jira: { _: [] }
}

为结果集生成另一个对象

{
    systemName: "jira",
    domains": []
}

并添加到结果

{
    _: [
        {
            systemName: "jira",
            domains: [] // <---+
        }               //     | domains and jira._ 
    ],                  //     | share the same 
    jira: {             //     | reference to the array
        _: []           // <---+
    }
}

为什么我需要对结果数组有两个不同的引用?

因为您需要一个特殊的结果数据结构。它是面向数组的,但访问是通过索引完成的。另一个结构可以通过属性直接访问,更容易访问,没有更多方法。

对于下一个组,如果在实际对象中是名为jira的属性,则返回'issue'的对象并执行另一个检查。这显然是在第一个循环中并非如此并且已添加。实际对象看起来像

{
    _: [
        {
            domainObject: "issue",
            eventTypes: []
        }
    ],
    issue: {
        _: []
    }
}

_[0].eventTypesissue._再次共享对数组的引用。

现在在数据的第一个循环结束时,哈希对象看起来像那样

{                                                  //   + same objects
    _: [                                           //               -+ result set
        {                                          //                |
            systemName: "jira",                    //                |
            domains: [                             //                |
                {                                  //         +      |
                    domainObject: "issue",         //         +      |
                    eventTypes: [                  //         +      |
                        {                          //    +    +      |
                            eventType: "creation", //    +    +      |
                            id: 39,                //    +    +      |
                            enabled: true          //    +    +      |
                        }                          //    +    +      |
                    ]                              //         +      |
                }                                  //         +      |
            ]                                      //                |
        }                                          //               -+
    ],                                             //
    jira: {                                        //
        _: [                                       //
            {                                      //         +
                domainObject: "issue",             //         +
                eventTypes: [                      //         +
                    {                              //    +    +
                        eventType: "creation",     //    +    +
                        id: 39,                    //    +    +
                        enabled: true              //    +    +
                    }                              //    +    +
                ]                                  //         +
            }                                      //         +
        ],                                         //
        issue: {                                   //
            _: [                                   //
                {                                  //    +
                    eventType: "creation",         //    +
                    id: 39,                        //    +
                    enabled: true                  //    +
                }                                  //    +
            ]                                      //
        }                                          //
    }                                              //
}                                                  //

数据数组循环到最后,所有组合现在都在对象中,并且已创建所有分组数组。然后只返回结果集。

&#13;
&#13;
function getGroupedData(data, groups, fn) {
    var keys = Object.keys(groups),
        result = [];

    data.forEach(function (a) {
        keys.reduce(function (r, k) {
            var temp,
                value = k.split('.').reduce(function (r, l) {
                    return (r || {})[l];
                }, a);
            if (!r[value]) {
                r[value] = { _: [] };
                temp = {};
                temp[k.split('.').pop()] = value;
                temp[groups[k]] = r[value]._;
                r._.push(temp);
            }
            return r[value];
        }, this)._.push(fn(a));
    }, { _: result });
    return result;
}


var data = [{ wrappedItem: { systemName: "jira", domainObject: "issue", eventType: "creation" }, "id": 39, enabled: true }, { wrappedItem: { systemName: "jira", domainObject: "issue", eventType: "predeletion" }, "id": 40, enabled: true }, { wrappedItem: { systemName: "jira", domainObject: "issue", eventType: "deletion" }, "id": 41, enabled: true }, { wrappedItem: { systemName: "jira", domainObject: "issue", eventType: "update" }, "id": 42, enabled: true }, { wrappedItem: { systemName: "jira", domainObject: "recquirement", eventType: "new" }, "id": 43, enabled: true }, { wrappedItem: { systemName: "jira", domainObject: "recquirement", eventType: "old" }, "id": 44, enabled: true }, { wrappedItem: { systemName: "bitbucket", domainObject: "branch", eventType: "creation" }, "id": 45, enabled: true }, { wrappedItem: { systemName: "bitbucket", domainObject: "branch", eventType: "deletion" }, "id": 46, enabled: true }, { wrappedItem: { systemName: "bitbucket", domainObject: "pull-request", eventType: "creation" }, "id": 47, enabled: true }],
    groups = { 'wrappedItem.systemName': 'domains', 'wrappedItem.domainObject': 'eventTypes' },
    fn = function (o) {
        return { eventType: o.wrappedItem.eventType, id: o.id, enabled: o.enabled };
    };

console.log(getGroupedData(data, groups, fn));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 1 :(得分:2)

使用<div ng-app="hello"> <div test-case condition="active">Active</div> <div test-case condition="pending">Pending</div> <div test-case condition="archived">Archived</div> <div test-case condition="finished">Finished</div> </div> 散列对象及其子对象,然后使用reduceObject.keys将这些散列对象转换为如下数组:

map

示例:

function group(arr) {
    // PHASE 1: wrap the object and the sub-objects into hash objects (group them)
    var hash = arr.reduce(function(h, o) {                                // for each object o in the array arr
        var sn = o.wrappedItem.systemName;                                // get the systemName
        var dob = o.wrappedItem.domainObject;                             // get the domainObject
        var ev = {eventType: o.wrappedItem.eventType, id: o.id, enabled: o.enabled}; // create an eventType object 
        if(h[sn]) {                                                       // if the systemName sn is already hashed
            if(h[sn].domainHash[dob])                                     // if the domain object dob is already hashed
                h[sn].domainHash[dob].eventTypes.push(ev);                // then push the eventType ev into its eventTypes array
            else                                                          // if not (the domain object is not hashed yet) then create a new domain object that have the eventType ev as the only item in its eventTypes array
                h[sn].domainHash[dob] = {domainObject: dob, eventTypes: [ev]};
        }
        else {                                                            // if not (the systemName sn is not hashed yet)
            h[sn] = {systemName: sn, domainHash: {}};                     // create a new systemName object with its domainHash object initialized with the domain object dob which is also initalized with the eventType ev
            h[sn].domainHash[dob] = {domainObject: dob, eventTypes: [ev]};
        }

        return h;
    }, {});

    // PHASE 2: unwrap the hash objects
    return Object.keys(hash).map(function(o) {                            // unwrap hash
        var domains = Object.keys(hash[o].domainHash).map(function(d) {   // unwrap domainHash
            return hash[o].domainHash[d];
        });
        delete hash[o].domainHash;                                        // remove the property domainHash
        hash[o].domains = domains;                                        // replace it with the property domains
        return hash[o];
    });
}

<强>解释

在第1阶段之后,我们得到一个这样的对象:

var array = [{"wrappedItem":{"systemName":"jira","domainObject":"issue","eventType":"creation"},"id":39,"enabled":true},{"wrappedItem":{"systemName":"jira","domainObject":"issue","eventType":"predeletion"},"id":40,"enabled":true},{"wrappedItem":{"systemName":"jira","domainObject":"issue","eventType":"deletion"},"id":41,"enabled":true},{"wrappedItem":{"systemName":"jira","domainObject":"issue","eventType":"update"},"id":42,"enabled":true},{"wrappedItem":{"systemName":"jira","domainObject":"recquirement","eventType":"new"},"id":43,"enabled":true},{"wrappedItem":{"systemName":"jira","domainObject":"recquirement","eventType":"old"},"id":44,"enabled":true},{"wrappedItem":{"systemName":"bitbucket","domainObject":"branch","eventType":"creation"},"id":45,"enabled":true},{"wrappedItem":{"systemName":"bitbucket","domainObject":"branch","eventType":"deletion"},"id":46,"enabled":true},{"wrappedItem":{"systemName":"bitbucket","domainObject":"pull-request","eventType":"creation"},"id":47,"enabled":true}];

function group(arr) {
    var hash = arr.reduce(function(h, o) {
        var sn = o.wrappedItem.systemName;
        var dob = o.wrappedItem.domainObject;
        var ev = {eventType: o.wrappedItem.eventType, id: o.id, enabled: o.enabled};
        if(h[sn]) {
            if(h[sn].domainHash[dob])
                h[sn].domainHash[dob].eventTypes.push(ev);
            else
                h[sn].domainHash[dob] = {domainObject: dob, eventTypes: [ev]};
        }
        else {
            h[sn] = {systemName: sn, domainHash: {}};
            h[sn].domainHash[dob] = {domainObject: dob, eventTypes: [ev]};
        }

        return h;
    }, {});

    return Object.keys(hash).map(function(o) {
        var domains = Object.keys(hash[o].domainHash).map(function(d) {
            return hash[o].domainHash[d];
        });
        delete hash[o].domainHash;
        hash[o].domains = domains;
        return hash[o];
    });
}


console.log(group(array));

这不是您想要的输出,散列可以更轻松地对项目进行分组,但输出将是一个对象。因此,为了获得所需的结果(数组),您还需要将哈希对象的子对象映射到数组中。

{
  "jira": {
    systemName: "jira",
    domainHash: {
      "issue": {
        domainObject: "issue",
        eventTypes: [...]
      },
      "other domain object": {
        domainObject: "other domain object",
        eventTypes: [...]
      },
      ...
    }
  },
  "other system name": {
    systemName: "other system name",
    domainHash: {
      "something": {
        domainObject: "something",
        eventTypes: [...]
      },
      ...
    }
  },
  ...
}

不仅需要映射的systemName对象,还需要映射domainObject对象(对于每个systemName对象):

var result = {
  hash["jira"],
  hash["other system name"],
  ...
];