如何使用数据分组将json数据转换为嵌套的json数据格式?

时间:2022-06-20 00:17:59

I have a json array as such

我有一个json数组

[{
  id:1,
  topicid : 1,
  Topic:Topic_name,
  categoryid:1,
  category : category_name,
  subcategoryid:1,
  subcategory : subcategory_name,
  pageid: 1,
  pageurl : pageurl_name
}]

I want to convert json to below structure , can you please any one help me make this using jquery or JavaScript .

我想将json转换为下面的结构,你能不能请任何人使用jquery或JavaScript来帮助我。

[{
    id :1
    topicid:tiopicid,
    text: "topic_name",
    items: [{
       categoryid:categoryid,
       text: "category_name" ,                           
       items: [{
           subcategoryid:subcategoryid
           text: "subcategory_name"  ,                                    
           items: [{
                 pageid:pageid,
                 text: "pageurl_name"                                        
                  }]
              }]
       }]
}]

1 个解决方案

#1


0  

Looks like you are interested in (roughly) normalizing a data set. In this case, grouping is the task. I cleaned up some of the field names to be more consistent and convenient for this particular solution.

看起来您对(粗略地)规范化数据集感兴趣。在这种情况下,分组是任务。我清理了一些字段名称,以便更加一致和方便地使用这个特定的解决方案。

Note that this will not stop the data from being duplicated in the different subgroups. As in, if the original data duplicates a pageid across different topics, both will be written into each topic (there's no database join or references in simple JSON). This may or may not be a problem for you.

请注意,这不会阻止数据在不同的子组中重复。同样,如果原始数据在不同主题上复制了一个pageid,则两者都将写入每个主题(没有数据库连接或简单JSON中的引用)。这对您来说可能是也可能不是问题。

I used Ramda.js, which is a functional Javascript library. This could also be done with lodash, underscore, or even straight JS. jQuery isn't going to help you out here; it's primarily a DOM compatibility library. One last thought before the code: doing this with loops is perfectly possible, but looping mutation is tricky, especially this many levels deep.

我使用了Ramda.js,它是一个功能性的Javascript库。这也可以通过lodash,下划线甚至直接JS来完成。 jQuery不会帮助你在这里;它主要是一个DOM兼容库。在代码之前的最后一个想法:使用循环执行此操作是完全可能的,但循环突变是棘手的,尤其是这么多级别。

Solution

The task is to take an array of objects, each with the same fields, and progressively group them into container objects. Each object holds the original id, the name of the id, and a list of items of sub-objects (the last id lacks this item list) The id buckets are:

任务是获取一组对象,每个对象具有相同的字段,并逐步将它们分组到容器对象中。每个对象包含原始id,id的名称和子对象项的列表(最后一个id缺少此项列表)id桶是:

var ids = ['topic', 'category', 'subcategory', 'page'];

So for every id, the data must be:

因此,对于每个id,数据必须是:

  1. Grouped into arrays of common ids
  2. 分成常见ID的数组

  3. Processed into the container object
  4. 处理到容器对象中

  5. If any ids remain, all sub-objects are dumped into items, being grouped again based on the remaining ids.
  6. 如果仍有任何ID,则将所有子对象转储到项目中,并根据剩余的ID再次进行分组。

Here's the relevant code:

这是相关的代码:

(groupIdList, currentDataSet) => {
  var currentId = R.head(groupIdList);
  var remainingIds = R.tail(groupIdList);

  var groupedByCurrentId = R.pipe(
    R.groupBy(R.prop(currentId + 'id')),
    R.map((lst) => {
      // by definition, all elements in the list
      // will have the same id (and barring bad initial data,
      // the same root value) So the guaranteed exisiting first
      // element is used as a template
      var first = R.head(lst);

      // if ids remain, populate the items field
      var obj = remainingIds.length > 0 ? {
        items: groupBy(remainingIds, lst)
      } : {};
      obj[currentId + 'id'] = first[currentId + 'id'];
      obj[currentId] = first[currentId];
      return obj;
    }),
    // groupBy returns an object key/values, and map perserves this.
    // but this function only cares about the values at this point
    R.values
  )(currentDataSet);
  return groupedByCurrentId;
};

/* jshint esnext: true */

var rawJson = [{
  "id": 1,
  "topicid": 1,
  "topic": "topic1",
  "categoryid": 1,
  "category": "cat1",
  "subcategoryid": 1,
  "subcategory": "subcat1",
  "pageid": 1,
  "page": "pageurl1"
}, {
  "id": 2,
  "topicid": 1,
  "topic": "topic1",
  "categoryid": 1,
  "category": "cat1",
  "subcategoryid": 2,
  "subcategory": "subcat2",
  "pageid": 1,
  "page": "pageurl1"
}, {
  "id": 4,
  "topicid": 1,
  "topic": "topic1",
  "categoryid": 1,
  "category": "cat1",
  "subcategoryid": 2,
  "subcategory": "subcat2",
  "pageid": 5,
  "page": "pageurl5"
}, {
  "id": 3,
  "topicid": 2,
  "topic": "topic2",
  "categoryid": 4,
  "category": "cat4",
  "subcategoryid": 6,
  "subcategory": "subcat6",
  "pageid": 10,
  "page": "pageurl10"
}];

var groupBy = (groupIdList, currentDataSet) => {
  var currentId = R.head(groupIdList);
  var remainingIds = R.tail(groupIdList);

  var groupedByCurrentId = R.pipe(
    R.groupBy(R.prop(currentId + 'id')),
    R.map((lst) => {
      // by definition, all elements in the list
      // will have the same id (and barring bad initial data,
      // the same root value) So the guaranteed exisiting first
      // element is used as a template
      var first = R.head(lst);

      // if ids remain, populate the items field
      var obj = remainingIds.length > 0 ? {
        items: groupBy(remainingIds, lst)
      } : {};
      obj[currentId + 'id'] = first[currentId + 'id'];
      obj[currentId] = first[currentId];
      return obj;
    }),
    // groupBy returns an object key/values, and map perserves this.
    // but this function only cares about the values at this point
    R.values
  )(currentDataSet);
  return groupedByCurrentId;
};

var ids = ['topic', 'category', 'subcategory', 'page'];

var output = groupBy(ids, rawJson);
console.log(output);

document.getElementById('results').innerText = JSON.stringify(output, null, 2);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.21.0/ramda.min.js"></script>
<pre id="results"></pre>

#1


0  

Looks like you are interested in (roughly) normalizing a data set. In this case, grouping is the task. I cleaned up some of the field names to be more consistent and convenient for this particular solution.

看起来您对(粗略地)规范化数据集感兴趣。在这种情况下,分组是任务。我清理了一些字段名称,以便更加一致和方便地使用这个特定的解决方案。

Note that this will not stop the data from being duplicated in the different subgroups. As in, if the original data duplicates a pageid across different topics, both will be written into each topic (there's no database join or references in simple JSON). This may or may not be a problem for you.

请注意,这不会阻止数据在不同的子组中重复。同样,如果原始数据在不同主题上复制了一个pageid,则两者都将写入每个主题(没有数据库连接或简单JSON中的引用)。这对您来说可能是也可能不是问题。

I used Ramda.js, which is a functional Javascript library. This could also be done with lodash, underscore, or even straight JS. jQuery isn't going to help you out here; it's primarily a DOM compatibility library. One last thought before the code: doing this with loops is perfectly possible, but looping mutation is tricky, especially this many levels deep.

我使用了Ramda.js,它是一个功能性的Javascript库。这也可以通过lodash,下划线甚至直接JS来完成。 jQuery不会帮助你在这里;它主要是一个DOM兼容库。在代码之前的最后一个想法:使用循环执行此操作是完全可能的,但循环突变是棘手的,尤其是这么多级别。

Solution

The task is to take an array of objects, each with the same fields, and progressively group them into container objects. Each object holds the original id, the name of the id, and a list of items of sub-objects (the last id lacks this item list) The id buckets are:

任务是获取一组对象,每个对象具有相同的字段,并逐步将它们分组到容器对象中。每个对象包含原始id,id的名称和子对象项的列表(最后一个id缺少此项列表)id桶是:

var ids = ['topic', 'category', 'subcategory', 'page'];

So for every id, the data must be:

因此,对于每个id,数据必须是:

  1. Grouped into arrays of common ids
  2. 分成常见ID的数组

  3. Processed into the container object
  4. 处理到容器对象中

  5. If any ids remain, all sub-objects are dumped into items, being grouped again based on the remaining ids.
  6. 如果仍有任何ID,则将所有子对象转储到项目中,并根据剩余的ID再次进行分组。

Here's the relevant code:

这是相关的代码:

(groupIdList, currentDataSet) => {
  var currentId = R.head(groupIdList);
  var remainingIds = R.tail(groupIdList);

  var groupedByCurrentId = R.pipe(
    R.groupBy(R.prop(currentId + 'id')),
    R.map((lst) => {
      // by definition, all elements in the list
      // will have the same id (and barring bad initial data,
      // the same root value) So the guaranteed exisiting first
      // element is used as a template
      var first = R.head(lst);

      // if ids remain, populate the items field
      var obj = remainingIds.length > 0 ? {
        items: groupBy(remainingIds, lst)
      } : {};
      obj[currentId + 'id'] = first[currentId + 'id'];
      obj[currentId] = first[currentId];
      return obj;
    }),
    // groupBy returns an object key/values, and map perserves this.
    // but this function only cares about the values at this point
    R.values
  )(currentDataSet);
  return groupedByCurrentId;
};

/* jshint esnext: true */

var rawJson = [{
  "id": 1,
  "topicid": 1,
  "topic": "topic1",
  "categoryid": 1,
  "category": "cat1",
  "subcategoryid": 1,
  "subcategory": "subcat1",
  "pageid": 1,
  "page": "pageurl1"
}, {
  "id": 2,
  "topicid": 1,
  "topic": "topic1",
  "categoryid": 1,
  "category": "cat1",
  "subcategoryid": 2,
  "subcategory": "subcat2",
  "pageid": 1,
  "page": "pageurl1"
}, {
  "id": 4,
  "topicid": 1,
  "topic": "topic1",
  "categoryid": 1,
  "category": "cat1",
  "subcategoryid": 2,
  "subcategory": "subcat2",
  "pageid": 5,
  "page": "pageurl5"
}, {
  "id": 3,
  "topicid": 2,
  "topic": "topic2",
  "categoryid": 4,
  "category": "cat4",
  "subcategoryid": 6,
  "subcategory": "subcat6",
  "pageid": 10,
  "page": "pageurl10"
}];

var groupBy = (groupIdList, currentDataSet) => {
  var currentId = R.head(groupIdList);
  var remainingIds = R.tail(groupIdList);

  var groupedByCurrentId = R.pipe(
    R.groupBy(R.prop(currentId + 'id')),
    R.map((lst) => {
      // by definition, all elements in the list
      // will have the same id (and barring bad initial data,
      // the same root value) So the guaranteed exisiting first
      // element is used as a template
      var first = R.head(lst);

      // if ids remain, populate the items field
      var obj = remainingIds.length > 0 ? {
        items: groupBy(remainingIds, lst)
      } : {};
      obj[currentId + 'id'] = first[currentId + 'id'];
      obj[currentId] = first[currentId];
      return obj;
    }),
    // groupBy returns an object key/values, and map perserves this.
    // but this function only cares about the values at this point
    R.values
  )(currentDataSet);
  return groupedByCurrentId;
};

var ids = ['topic', 'category', 'subcategory', 'page'];

var output = groupBy(ids, rawJson);
console.log(output);

document.getElementById('results').innerText = JSON.stringify(output, null, 2);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.21.0/ramda.min.js"></script>
<pre id="results"></pre>