Home > Mobile >  How do I find a value in a parent key of a specific child in a JSON data set with javascript?
How do I find a value in a parent key of a specific child in a JSON data set with javascript?

Time:03-23

How do I find a value in a parent key of a specific child in a JSON data set? My JSON data looks something like this:

DATA = {
    "result":"Ok",
    "data":[{
        "orderNumber":"Order1",
        "anyKey":"something else",
        "samples":[{
            "sampleNumber":"sample1",
            "anyOtherKey":"something",
            "item123":"abc 123"
        },{
            "sampleNumber":"sample2",
            "anyOtherKey":"something",
            "item123":"def 123"
        }],
        "tests":[{
            "testNumber":"DP2200200-01",
            "testTypeName":"testtype1"
        }]
    },{
        "orderNumber":"Order2",
        "anyKey":"something",
        "samples":[{
            "sampleNumber":"sample2",
            "anyKey":"something",
        }],
        "tests":[{
            "testNumber":"test2",
            "testTypeName":"testtype2"
        }]
    },{
        "orderNumber":"Order3",
        "anyKey":"something",
        "samples":[{
            "sampleNumber":"sample1",
            "anyOtherKey":"something",
            "item123":"xyz 123"
        }]
    }
]}

I need a way to search for string (like abc) inside item123 and return the OrderNumber belonging to it. So far I did look it up by

  let keyword = "abc"
  let mydata = DATA.data.find(order => order.samples.find(sam => sam.item123.includes(keyword)));
  if ( typeof mydata == 'undefined') {
    document.getElementById("orderNumber").innerHTML = "nothing found :-(";
  } else {
    var myOutput = mydata ["orderNumber"];
    document.getElementById("orderNumber").innerHTML = myOutput ;
  }

This works fine as long as the child has the item123, so it works for Order1 but fails for Order3, because Order2 does not have the item123. However some sets don't have this property.

Another drawback is that it only finds the first occurrence. How can I find all occurrences and return the associated sampleNumber as well?

CodePudding user response:

How can I find all occurrences and return the associated sampleNumber as well?

I assume that means you want an array containing (say) objects with those two properties.

You just need nested loops and optional chaining:

const results = [];
for (const element of DATA.data) {
    for (const {item123, sampleNumber} of element.samples) {
        if (item123?.includes(keyword)) {
        //         ^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− optional chaining
            results.push({item123, sampleNumber});
        }
    }
}

If you can't use optional chaining in your environment yet, you can just do a truthiness test:

        if (item123 && item123.includes(keyword)) {

Live example:

const DATA = {
    "result":"Ok",
    "data":[{
        "orderNumber":"Order1",
        "anyKey":"something else",
        "samples":[{
            "sampleNumber":"sample1",
            "anyOtherKey":"something",
            "item123":"abc 123"
        },{
            "sampleNumber":"sample2",
            "anyOtherKey":"something",
            "item123":"def 123"
        }],
        "tests":[{
            "testNumber":"DP2200200-01",
            "testTypeName":"testtype1"
        }]
    },{
        "orderNumber":"Order2",
        "anyKey":"something",
        "samples":[{
            "sampleNumber":"sample2",
            "anyKey":"something",
        }],
        "tests":[{
            "testNumber":"test2",
            "testTypeName":"testtype2"
        }]
    },{
        "orderNumber":"Order3",
        "anyKey":"something",
        "samples":[{
            "sampleNumber":"sample1",
            "anyOtherKey":"something",
            "item123":"abc 123"
        }]
    }
]};
const keyword = "abc";

const results = [];
for (const element of DATA.data) {
    for (const {item123, sampleNumber} of element.samples) {
        if (item123?.includes(keyword)) {
            results.push({item123, sampleNumber});
        }
    }
}
console.log(results);
.as-console-wrapper {
    max-height: 100% !important;
}

(Note that I added the keyword to a second element in there so you could see all of them being found.)

You can also do it with map and flat (though not, sadly, flatMap as we need a depth greater than 1):

const results = DATA.data.map(element =>
    element.samples.map(({item123, sampleNumber}) =>
        item123?.includes(keyword) ? {item123, sampleNumber} : []
    )
).flat(Infinity);

...but I wouldn't. Harder to read, harder to debug, and involves creating unnecessary temporary arrays. Still, some folks like that kind of thing, so...

Live example:

const DATA = {
    "result":"Ok",
    "data":[{
        "orderNumber":"Order1",
        "anyKey":"something else",
        "samples":[{
            "sampleNumber":"sample1",
            "anyOtherKey":"something",
            "item123":"abc 123"
        },{
            "sampleNumber":"sample2",
            "anyOtherKey":"something",
            "item123":"def 123"
        }],
        "tests":[{
            "testNumber":"DP2200200-01",
            "testTypeName":"testtype1"
        }]
    },{
        "orderNumber":"Order2",
        "anyKey":"something",
        "samples":[{
            "sampleNumber":"sample2",
            "anyKey":"something",
        }],
        "tests":[{
            "testNumber":"test2",
            "testTypeName":"testtype2"
        }]
    },{
        "orderNumber":"Order3",
        "anyKey":"something",
        "samples":[{
            "sampleNumber":"sample1",
            "anyOtherKey":"something",
            "item123":"abc 123"
        }]
    }
]};
const keyword = "abc";

const results = DATA.data.map(element =>
    element.samples.map(({item123, sampleNumber}) =>
        item123?.includes(keyword) ? {item123, sampleNumber} : []
    )
).flat(Infinity);
console.log(results);
.as-console-wrapper {
    max-height: 100% !important;
}

CodePudding user response:

First you need to filter out the objects

const filteredData = DATA.data.filter(d => d.samples.find(s => s?.item123?.includes('abc')));

You can then extract the value you need. Here i am extracting orderNumber.

const orderNumbers = filteredData.map(fd => fd.orderNumber);

You can even use flatMap instead of filter and map to filter and extract in the same loop.

  • Related