0

Good morning, I have an object with this structure :

{
  instituts: {
    default: 999,
    users: { default: 888, email: 777 },
    docs: undefined,
    exams: { price: 3 },
    empowermentTests: 2,
    sessionsHist: 3
  },
  exams: { default: 0 },
  countries: 1,
  levels: 1,
  roles: { default: 1 },
  sessions: 1,
  tests: 1,
  users: { default: 3 },
  options: undefined,
  skills: { default: undefined }
}

And i have an array giving the path like ["instituts", "users"].

Thank to this array of paths, i want to parse my object and return the value of : instituts.users.default ( 'default', because after the path "users", there are not other entries and users type is an object)

An other example : path : ['instituts', "users", "email"] i want to have the value of : instituts.users.email (not 'default', cause in the object structure, email, is an integer, not an objet ).

I hope i am clear enought.

I tryed many things but i am lost with ES6 function : "filter / reduce / map ..."

Thank you for the help you can give.

  • Near duplicate: https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-and-arrays-by-string-path – T.J. Crowder Aug 24 '21 at 13:38

3 Answers3

2

I think this does what you're looking for:

const getPath = ([p, ...ps]) => (o) =>
  p == undefined ? o : getPath (ps) (o && o[p])

const getPowerNeed = (path, obj, node = getPath (path) (obj)) =>
  Object (node) === node && 'default' in node ? node .default : node
  
const input = {instituts: {default: 999, users: {default: 888, email: 777}, docs: undefined, exams: {price: 3}, empowermentTests: 2, sessionsHist: 3}, exams: {default: 0}, countries: 1, levels: 1, roles: {default: 1}, sessions: 1, tests: 1, users: {default: 3}, options: undefined, skills: {default: undefined}}

console .log (getPowerNeed (['instituts', 'users'], input)) //=> 888
console .log (getPowerNeed (['instituts', 'users', 'email'], input)) //=> 777
console .log (getPowerNeed (['instituts'], input)) //=> 999
console .log (getPowerNeed (['instituts', 'exams', 'price'], input)) //=> 3

I'm making the assumption that if the default value is not to be found, then you want to return the actual value if it exists. Another reasonable reading of the question is that you want to return the literal string 'instituts.users.email'. That wouldn't be much more difficult to do if necessary.

The utility function getPath takes a path and returns a function from an object to the value at that path in the object, returning undefined if there are any missing nodes along that path. The main function is getPowerNeed, which wraps some default-checking around a call the getPath.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • 1
    I like the style of your solution. I will put a focus on your lines. Thank you. the path is on an array form, so your solution look great. – Baptiste Bauer Aug 24 '21 at 23:15
0

My code :

i receive URL : /api/instituts/1/users/email for example My express middleware is named : isAuthorized.

My object with the power ( for the giving roles of users ) is named : powerNeedByHttpMethod

The "paths" are giving by splitting and filterring URL :

const paths = req.url.split('/').filter(e => e !== 'api' && !parseInt(e) && e !== '');

I tryed to made this by following an example found on this board :

getPowerNeed(obj, paths) {
    if (!obj) return null;

    const partial = paths.shift(),
          filteredKeys = Object.keys(obj).filter(k => k.toLowerCase().includes(partial));
  
    if (!filteredKeys.length) return null; // no keys with the path found
    
    return filteredKeys.reduce((acc, key) => {
      if(!paths.length) return { ...acc, [key]: obj[key] }
      
      const nest = module.exports.getPowerNeed(obj[key], [...paths]) // filter another level
      return nest ? { ...acc, [key]: nest } : acc
    }, null)
}
0

i found an other solutions :

const routes = ['options', 'arbo1', 'arbo2'];
const objPower = {
  instituts: {
    default: 999,
    users: { default: 888, email: 777 },
    docs: undefined,
    exams: { price: 3 },
    empowermentTests: 2,
    sessionsHist: 3
  },
  exams: { default: 0 },
  countries: 1,
  levels: 1,
  roles: { default: 1 },
  sessions: 1,
  tests: 1,
  users: { default: 3 },
  options: { 
   default: 19822,
    arbo1 : { 
        arbo2 : {
        arbo3: 3
        }}},
  skills: { default: undefined }
}



function getPower(objPower, entries, defaultPowerNeeded) {

    // On extrait le premier élément de la route et on le retire.
  const firstEntry = entries.shift();
    // Object.keys to list all properties in raw (the original data), then
  // Array.prototype.filter to select keys that are present in the allowed list, using
  // Array.prototype.includes to make sure they are present
  // Array.prototype.reduce to build a new object with only the allowed properties.
  const filtered = Object.keys(objPower)
  .filter(key => key === firstEntry)
  .reduce((obj, key) => {
    obj[key] = objPower[key];
    if(objPower[key].default) {
        defaultPowerNeeded = objPower[key].default;
    }
    return obj;
  }, {})[firstEntry];
  
  if(!entries.length) {
    if(typeof filtered === 'object') {
        if(filtered.default) {
        return filtered.default;
      }
      else {
       return defaultPowerNeeded;
      }
     
    }
    else return filtered;
  }
  return getPower(filtered,entries, defaultPowerNeeded);
}


const defaultPowerNeeded = 12;
const result = getPower(objPower, routes, defaultPowerNeeded);
console.log(result);