0

I have a json object, and i need to add key value pair in the object at the given path.

const data = {
  "hosts": {
    "static": {
      "domain": "http://api-azure-dev.atc.com",
      "port": 80
    },
    "azure": {
      "domain": "http://api-azure-dev.atc-v8.com",
      "port": 80
    }
  },
  "paths": {
    "static": {
      "cities": {
        "hostKey": "static",
        "path": "/cf/v2/lookups/cities",
        "method": "GET"
      }
    }
  }
};

here i need to add some value at path $.paths.static.getCountryCode, this is a jsonpath notation, where $ represents root. then the updated value is returned.

const newConsul = {
        "hostKey": "azure",
        "path": "/v8/v1/lookups/countryCode/{country}",
        "method": "get"
    };

how to create a function which could insert the value of given newConsul into the data object? so that the final data object would look like:

const data = {
  "hosts": {
    "static": {
      "domain": "http://api-azure-dev.atc.com",
      "port": 80
    },
    "azure": {
      "domain": "http://api-azure-dev.atc-v8.com",
      "port": 80
    }
  },
  "paths": {
    "static": {
      "cities": {
        "hostKey": "static",
        "path": "/cf/v2/lookups/cities",
        "method": "GET"
      },
      "getCountryCode": {
         "hostKey": "azure",
         "path": "/v8/v1/lookups/countryCode/{country}",
         "method": "get"
      }
    }
  }
};
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Shubham Shaw
  • 841
  • 1
  • 11
  • 24

1 Answers1

0

Since one always needs to split the string based path value and then needs to iterate the resulting key-array in order to programmatically access the next nested property value, one could do both, choosing a reduce based approach and starting first with just the implementation of a get method (in order to demonstrate the reduce based access).

There the initialValue would be the to be iterated object where, with each iteration step, one would try to safely access the next nested value via e.g. reference?.[key] where reference is the recent reference into the originally passed object and ?.[key] is the fail safe attempt of accessing the next nested value by making use of Optional Chaining. The next iteration step does pass the result of this access as first argument into the reducer function again. It also is the reduce methods return value once the key-array has been finished processing.

A set method would be based on the formerly implemented get. Here one needs to take care not only of accessing the next nested property value as before, but also in case it does not exist of creating it. In the latter case one has to figure out whether to assign the additionally passed data payload or to assign an empty object instead.

function get(path = '', obj = {}) {
  return String(path)
    // get rid of the optional/not needed leading characters ...  '$.'
    .replace(/^\$\./, '')
    // split the path name into an array/list of keys.
    .split('.')
    // programmatically access the next nested property value.
    .reduce((reference, key) =>
      reference?.[key], Object(obj)
    );
}
function set(path = '', obj = {}, data) {
  return String(path)
    .replace(/^\$\./, '')
    .split('.')
    // programmatically access or create the next nested property value
    // until the target key is reached and the passed data gets assigned.
    .reduce((reference, key, idx, listOfKeys) => {

      const value = (idx >= listOfKeys.length - 1)
        ? (structuredClone?.(data) ?? data)
        : {};

      return reference.hasOwnProperty(key)
        ? reference[key]
        : Object.assign(reference, { [ key ]: value })[key];

    }, Object(obj));
}

const data = {
  hosts: {
    static: {
      domain: 'http://api-azure-dev.atc.com',
      port: 80,
    },
    azure: {
      domain: 'http://api-azure-dev.atc-v8.com',
      port: 80,
    },
  },
  paths: {
    static: {
      cities: {
        hostKey: 'static',
        path: '/cf/v2/lookups/cities',
        method: 'GET',
      },
    },
  },
};
console.log({ data });

console.log(
  "get('hosts.static', data) ...",
  get('hosts.static', data),
);
console.log(
  "get('$.hosts.static.domain', data) ...",
  get('$.hosts.static.domain', data),
);
console.log(
  "get('$.hosts.static.foo', data) ...",
  get('$.hosts.static.foo', data),
);

console.log(`
set('$.paths.static.getCountryCode', data, {
 hostKey: 'azure',
 path: '/v8/v1/lookups/countryCode/{country}',
 method: 'get'
}) ...`,
  set('$.paths.static.getCountryCode', data, {
   hostKey: 'azure',
   path: '/v8/v1/lookups/countryCode/{country}',
   method: 'get'
  })
);
console.log({ data });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37