简体   繁体   中英

Finding JSON Array Object Values by KeyName

I am looking for a HashMap sort of implementation in Javascript for JSON for the following case.

I have the JSON with following structure:

{
"level1": {
    "level2": [{
        "product1": [
            "item1",
            "item2"
        ]
    }, {
        "product2": [
            "item1",
            "item2"
        ]
    }, {
        "product3": [
            "item5",
            "item6"
        ]
    }]
}
}

For my use case, I get a value , say 'product3', I want to find values for this key ie "item5", "item6". I have a way, that i can loop through the entire level2 object but want to know if I can simply use key to find values.

You can build yourself either an object or (in ES2015) a Map :

Here's an ES5 example using an object:

var map = Object.create(null);
data.level1.level2.forEach(function(entry) {
    Object.keys(entry).forEach(function(key) {
        map[key] = entry;
    });
});

Live example:

 var data = { "level1": { "level2": [{ "product1": [ "item1", "item2" ] }, { "product2": [ "item1", "item2" ] }, { "product3": [ "item5", "item6" ] }] } }; var map = Object.create(null); data.level1.level2.forEach(function(entry) { Object.keys(entry).forEach(function(key) { map[key] = entry; }); }); var name = "product2"; console.log(map[name]); 

We create the object ( map ) using Object.create(null) so that it doesn't have a prototype, and so doesn't have the pre-existing inherited properties like toString and valueOf .

The inner loop, on the result of Object.keys , is necessary because each object in the level2 array has a different name for its only property. That's an unusual and a bit awkward structure.

In ES2015 (aka "ES6") with Map , it's very similar you just use new Map and set :

var map = new Map();
data.level1.level2.forEach(function(entry) {
    Object.keys(entry).forEach(function(key) {
        map.set(key, entry);
    });
});

Live example:

 var data = { "level1": { "level2": [{ "product1": [ "item1", "item2" ] }, { "product2": [ "item1", "item2" ] }, { "product3": [ "item5", "item6" ] }] } }; var map = new Map(); data.level1.level2.forEach(function(entry) { Object.keys(entry).forEach(function(key) { map.set(key, entry); }); }); var name = "product2"; console.log(map.get(name)); 

"One-line" optimized solution using Array.some , Array.indexOf and Object.keys functions (no need to iterate through all "product" objects):

// json is your initial object
var key = 'product3', values;
json['level1']['level2'].some((v) => Object.keys(v).indexOf(key) !== -1 && (values = v[key]), values);

console.log(values);  // ["item5", "item6"]

Explanation :
arr.some(callback[, thisArg]) - This function returns true if the callback function returns a truthy value for any array element; In my example values becomes thisArg parameter which should contain values of the desired "keyName".
It will iterate through all "product" objects, but will stop looping immediately if the required keyName is found amoung the properties of the current object ( Object.keys(v).indexOf(key) !== -1 ).
As a concurrent condition it should save the values of found object which can be achieved with truthy assignment expression && (values = v[key]) .
That's all.

You could just transform data to different structure.

 const data = { "level1": { "level2": [{ "product1": [ "item1", "item2" ] }, { "product2": [ "item3", "item4" ] }, { "product3": [ "item5", "item6" ] }] }, "level1b": { "level2": [{ "product1": [ "item1b", "item2" ] }, { "product2": [ "item3", "item4" ] }, { "product3": [ "item5", "item6" ] }] } }; const transformed = Object .keys(data) .reduce((obj, key) => { const value = data[key]; return Object.assign(obj, {[key]: transformLvl2(value)}); }, {}); console.log(transformed.level1.level2.product2); console.log(transformed.level1.level2.product1); console.log(transformed.level1.level2.product3); console.log(transformed.level1b.level2.product1); function transformLvl2(level2) { return Object .keys(level2) .reduce((obj, key) => { const value = level2[key]; return Object.assign(obj, {[key]: transformLvl3(value)}); }, {}); } function transformLvl3(level3) { return level3 .reduce((obj, value) => { return Object.assign(obj, value); }, {}); } 

try (assuming that level1 and level2 is generic)

 var obj = { "level1": { "level2": [{ "product1": [ "item1", "item2" ] }, { "product2": [ "item1", "item2" ] }, { "product3": [ "item5", "item6" ] }] } }; var keyName = "product3"; var items = []; Object.keys(obj).forEach(function(key) { Object.keys( obj[key] ).forEach(function(key1){ obj[key][key1].forEach(function(obj1){ Object.keys(obj1).forEach(function(key2) { if (key2 == keyName) { items = items.concat(obj1[key2]); } }); }); }); }); console.log(items); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM