1

I'm trying to get a certain structure for my JSON but I'm struggling in the process and get an infinite loop.

I managed to get to a certain point with the original file by using the reduce() method, but I'm stuck with the last step.

here is the JSON:

{
    "someNumbers_like_15269": {
        "someNumbers_like_35896": [{
            "TestPoint": "A",
            "ItemNo": "12110",
            "TestDesc": "Penalty Points"
        }, {
            "TestPoint": "A",
            "ItemNo": "12110",
            "TestDesc": "Brix"
        }, {
            "TestPoint": "B",
            "ItemNo": "12110",
            "TestDesc": "Texture"
        }, {
            "TestPoint": "B",
            "ItemNo": "12110",
            "TestDesc": "Viscosity"
        }, {
            "TestPoint": "C",
            "ItemNo": "12110",
            "TestDesc": "PH"
        }, {
            "TestPoint": "C",
            "ItemNo": "12110",
            "TestDesc": "Taste"
        }]
    }
}

And the desired result

{
"someNumbers_like_15269": {
    "someNumbers_like_35896": {
        "ItemNo": "12110",
        "someOtherThing": "blabla",
        "Test": [{
            "TestPoint": "A",
            "TestDesc": ["Penalty Points", "Brix"]
        }, {
            "TestPoint": "B",
            "TestDesc": ["Texture", "Viscosity"]
        }, {
            "TestPoint": "C",
            "TestDesc": ["PH", "Taste"]
        }]
    }
}

} PS: There will be multiple CC and multiple Batches, the JSON as more than 85 thousand lines

**

my original attempt can be found in here

**

1
  • 3
    why do people downvote without any comment? Commented Jun 8, 2018 at 9:06

2 Answers 2

3

Use Array.reduce, Array.forEach, Object.values and Object.entries

var data = {"someNumbers_like_15269":{"someNumbers_like_35896":[{"TestPoint":"A","ItemNo":"12110","TestDesc":"Penalty Points"},{"TestPoint":"A","ItemNo":"12110","TestDesc":"Brix"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Texture"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Viscosity"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"PH"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"Taste"}],"someNumbers_like_21":[{"TestPoint":"A","ItemNo":"12110","TestDesc":"Penalty Points"},{"TestPoint":"A","ItemNo":"12110","TestDesc":"Brix"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Texture"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Viscosity"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"PH"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"Taste"}]},"someNumbers_like_15270":{"someNumbers_like_35800":[{"TestPoint":"A","ItemNo":"12110","TestDesc":"Penalty Points"},{"TestPoint":"A","ItemNo":"12110","TestDesc":"Brix"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Texture"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Viscosity"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"PH"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"Taste"}]}};

// Iterate for all first level values
Object.values(data).forEach(v => {
  // Iterate for all second level values
  Object.entries(v).forEach(([k,v1]) => {
    // Set the updated value back in object
    v[k] = Object.values(v1.reduce((a,{TestDesc, TestPoint, ...rest}) => {
      a[TestPoint] ? a[TestPoint].TestDesc.push(TestDesc) : a[TestPoint] = {TestPoint, ...rest, TestDesc : [TestDesc]};
      return a;
      }, {}));
  });
})

console.log(data);

EDIT

var data = {"someNumbers_like_15269":{"someNumbers_like_35896":[{"TestPoint":"A","ItemNo":"12110","TestDesc":"Penalty Points"},{"TestPoint":"A","ItemNo":"12110","TestDesc":"Brix"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Texture"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Viscosity"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"PH"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"Taste"}],"someNumbers_like_21":[{"TestPoint":"A","ItemNo":"12110","TestDesc":"Penalty Points"},{"TestPoint":"A","ItemNo":"12110","TestDesc":"Brix"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Texture"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Viscosity"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"PH"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"Taste"}]},"someNumbers_like_15270":{"someNumbers_like_35800":[{"TestPoint":"A","ItemNo":"12110","TestDesc":"Penalty Points"},{"TestPoint":"A","ItemNo":"12110","TestDesc":"Brix"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Texture"},{"TestPoint":"B","ItemNo":"12110","TestDesc":"Viscosity"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"PH"},{"TestPoint":"C","ItemNo":"12110","TestDesc":"Taste"}]}};

// Iterate for all first level values
Object.values(data).forEach(v => {
  // Iterate for all second level values
  Object.entries(v).forEach(([k,v1]) => {
    let {TestDesc, TestPoint, ...rest} = v1[0];
    let Test = Object.values(v1.reduce((a,{TestDesc, TestPoint}) => {
      a[TestPoint] ? a[TestPoint].TestDesc.push(TestDesc) : a[TestPoint] = {TestPoint, TestDesc : [TestDesc]};
      return a;
    }, {}));
    v[k] = {...rest, Test};
  });
})

console.log(data);

Sign up to request clarification or add additional context in comments.

6 Comments

what if I have more keys, not only TestDesc, TestPoint and ItemNo?
it's working, thanks! but I noticed some useless repetition in my desired result, can you have a look at the updated question?
@Jonathan - Can you provide more information on the repetition? What needs to be improved?
I moved the other keys right after the second level and moved testPoint and TestDescription into the 3rd level inside a Test object. See my desired result from the question
@Jonathan - What about the other properties if any? Also is ItemNo unique in an array?
|
3

Taking the original data and respecting any nested objects and arrays, you could take a nested approach and given key and value for grouping.

The part of Array.isArray(w) ... could be replaced by a hard coded property check, or just deleted if all keys have an array for grouping.

Outer object's keys and values, denoted by k and v, and inner keys and values of v, denoted by l and w, where all objects are destructed and rebuild with this pattern:

Object.assign(...Object
    .entries(object)
    .map(([key, value]) => ({ [key]: value })
)

in this example and for the next level, value in ({ [key]: value }) is replaced by another same structure for the nested object.

Finally a reduce takes palce and it looks for an object in the accumulator if the wanted key for grouping is found. if not it generates a new object and later it pushes the grouping vlaue to the array for collecting this item.

var data = { CC1: { Batch1: [{ TestPoint: "A", ItemNo: "12110", TestDesc: "Penalty Points" }, { TestPoint: "A", ItemNo: "12110", TestDesc: "Brix" }, { TestPoint: "B", ItemNo: "12110", TestDesc: "Texture" }, { TestPoint: "B", ItemNo: "12110", TestDesc: "Viscosity" }, { TestPoint: "C", ItemNo: "12110", TestDesc: "PH" }, { TestPoint: "C", ItemNo: "12110", TestDesc: "Taste" }] } },
    group = { key: 'TestPoint', value: 'TestDesc' },
    result = Object.assign(...Object.entries(data).map(([k, v]) => ({
        [k]: Object.assign(...Object.entries(v).map(([l, w]) => ({
            [l]: Array.isArray(w)
                ? w.reduce((r, o) => {
                    var item = r.find(p => o[group.key] === p[group.key]);
                    if (!item) {
                        r.push(item = Object.assign({}, o, { [group.value]: [] }));
                    }
                    item[group.value].push(o[group.value]);
                    return r;
                }, [])
                : w
        })))
    })));

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

Finally a complete dynamic recursive approach for nested objects. If an array is found, the grouping takes place.

This code prevents duplicate entries for grouped values.

function groupBy(object, by) {
    return Array.isArray(object)
        ? object.reduce((r, o) => {
            var item = r.find(({ [by.key]: v }) => o[by.key] === v);
            if (!item) {
                item = Object.assign({}, o, { [by.value]: [] });
                r.push(item);
            }
            if (!item[by.value].includes(o[by.value])) {
                item[by.value].push(o[by.value]);
            }
            return r;
        }, [])
        : Object.assign(...Object
            .entries(object)
            .map(([key, value]) => ({ [key]: groupBy(value, by) }))
        );
}

var data = { CC1: { Batch1: [{ TestPoint: "A", ItemNo: "12110", TestDesc: "Penalty Points" }, { TestPoint: "A", ItemNo: "12110", TestDesc: "Brix" }, { TestPoint: "B", ItemNo: "12110", TestDesc: "Texture" }, { TestPoint: "B", ItemNo: "12110", TestDesc: "Viscosity" }, { TestPoint: "C", ItemNo: "12110", TestDesc: "PH" }, { TestPoint: "C", ItemNo: "12110", TestDesc: "Taste" }] } },
    result = groupBy(data, { key: 'TestPoint', value: 'TestDesc' });

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

2 Comments

can I have some comments on what is doing what?
it's working, thanks! but I noticed some useless repetition in my desired result, can you have a look at the updated question?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.