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.