Search code examples
javascriptinternet-explorer-11ecmascript-5

getPathValue() function for deep objects


This is a follow-up question to this: getPathValue() function for deep objects with arrays and with packed JSON

The accepted answer works very well in most situations:

function getPathValue(object, path) {
    return path
       .replace(/\[/g, '.')
       .replace(/\]/g, '')
       .split('.')
       .reduce(function (o, k) {
           return (typeof o === 'string' ? JSON.parse(o) : (o || {}))[k];
       }, object);
}

I now have a new requirement. I need it to work with arrays in the root level. For example, this object:

[{"currencyPair":"EUR/USD","timestamp":"1546028298698","bidBig":"1.14","bidPips":"450","offerBig":"1.14","offerPips":"457","high":"1.14253","low":"1.14732","open":"1.14305"},{"currencyPair":"USD/JPY","timestamp":"1546028299095","bidBig":"110.","bidPips":"326","offerBig":"110.","offerPips":"336","high":"110.222","low":"111.062","open":"111.012"},{"currencyPair":"GBP/USD","timestamp":"1546028246468","bidBig":"1.26","bidPips":"974","offerBig":"1.26","offerPips":"988","high":"1.26350","low":"1.27087","open":"1.26505"},{"currencyPair":"EUR/GBP","timestamp":"1546028296658","bidBig":"0.90","bidPips":"127","offerBig":"0.90","offerPips":"140","high":"0.90034","low":"0.90601","open":"0.90355"},{"currencyPair":"USD/CHF","timestamp":"1546028296551","bidBig":"0.98","bidPips":"470","offerBig":"0.98","offerPips":"481","high":"0.97896","low":"0.99113","open":"0.98854"},{"currencyPair":"EUR/JPY","timestamp":"1546028299289","bidBig":"126.","bidPips":"322","offerBig":"126.","offerPips":"336","high":"126.256","low":"127.204","open":"127.008"},{"currencyPair":"EUR/CHF","timestamp":"1546028296543","bidBig":"1.12","bidPips":"714","offerBig":"1.12","offerPips":"726","high":"1.12146","low":"1.13180","open":"1.12920"},{"currencyPair":"USD/CAD","timestamp":"1546028299908","bidBig":"1.36","bidPips":"470","offerBig":"1.36","offerPips":"485","high":"1.35946","low":"1.36613","open":"1.36142"},{"currencyPair":"AUD/USD","timestamp":"1546028296222","bidBig":"0.70","bidPips":"445","offerBig":"0.70","offerPips":"453","high":"0.70238","low":"0.70695","open":"0.70288"},{"currencyPair":"GBP/JPY","timestamp":"1546028297767","bidBig":"140.","bidPips":"123","offerBig":"140.","offerPips":"148","high":"139.495","low":"140.628","open":"140.462"}]

I want to retain all of the functionality of the previously accepted answer, but in addition, I'd like to be able to retrieve specific array elements and even specific key values within specific array elements. For example,

value = getPathValue(obj, '[0]');

...which should return only this string:

{"currencyPair":"EUR/USD","timestamp":"1546028298698","bidBig":"1.14","bidPips":"450","offerBig":"1.14","offerPips":"457","high":"1.14253","low":"1.14732","open":"1.14305"}

or

value = getPathValue(obj, '[3].bidPips');

...which would return:

"0.90"

Solution

  • Change:

    .split('.')
    

    By:

    .split('.').filter(Boolean)
    

    It will remedy a dot that got placed at the very beginning of the string, which is what happens when the input starts with a [, like in [0].

    Demo:

    function getPathValue(object, path) {
        return path
           .replace(/\[/g, '.')
           .replace(/\]/g, '')
           .split('.').filter(Boolean)
           .reduce(function (o, k) {
               return (typeof o === 'string' ? JSON.parse(o) : (o || {}))[k];
           }, object);
    }
    
    var obj = [{"currencyPair":"EUR/USD","timestamp":"1546028298698","bidBig":"1.14","bidPips":"450","offerBig":"1.14","offerPips":"457","high":"1.14253","low":"1.14732","open":"1.14305"},{"currencyPair":"USD/JPY","timestamp":"1546028299095","bidBig":"110.","bidPips":"326","offerBig":"110.","offerPips":"336","high":"110.222","low":"111.062","open":"111.012"}];
    
    value = getPathValue(obj, '[0].bidPips');
    
    console.log(value);

    It can be done easier though, by replacing the replace and split calls by one match call:

    function getPathValue(object, path) {
        return path
           .match(/[^[\].]+/g)
           .reduce(function (o, k) {
               return (typeof o === 'string' ? JSON.parse(o) : (o || {}))[k];
           }, object);
    }
    
    var obj = [{"currencyPair":"EUR/USD","timestamp":"1546028298698","bidBig":"1.14","bidPips":"450","offerBig":"1.14","offerPips":"457","high":"1.14253","low":"1.14732","open":"1.14305"},{"currencyPair":"USD/JPY","timestamp":"1546028299095","bidBig":"110.","bidPips":"326","offerBig":"110.","offerPips":"336","high":"110.222","low":"111.062","open":"111.012"}];
    value = getPathValue(obj, '[0].bidPips');
    
    console.log(value);