1

I have a JS Object that may look like one of the following:

// Example #1:
var data = {
    product: {
        value1: 'v1',
        value2: 2
    }
}
// Example #2:    
var data = {
    order: {
        value1: 1
    }
}
// Example #3:    
var data = {
    value1: 1
}

What I'd like to achieve:

var inputName = 'product[value1]';
var data = {
    product: {
        value1: 'v1',
        value2: 2
    }
}
var value = something(data, inputName); // should return v1

inputName and data can change, I can have any of the above data Objects with an inputName like 'product[value2]', 'order[value1]', 'value1'.

My guess is to use regex and get both attribute names. Is the a better way?

6
  • Are you unsure because of the changing keys (product, order) or because of the nested changing keys (value1, value2) Commented Aug 29, 2017 at 9:00
  • I'm searching for a solution that would let me get the value without breaking the inputName (e.g. I'm searching for product[value1] and would like to get it similar to data['value1'], but data['product[value1]'] woudn't work). Commented Aug 29, 2017 at 9:03
  • 2
    You can see your object as a tree with nodes and leaves. Start searching from the root, using Object.keys and if the value is an object, perform a recursion step. Otherwise, check the value if it matches your search. Commented Aug 29, 2017 at 9:03
  • What will be result of the search? "The search in the last example is simple" post the code for the simple example. Commented Aug 29, 2017 at 9:03
  • Providing some sample search queries with expected results would make it easier to understand. Commented Aug 29, 2017 at 9:06

4 Answers 4

1

you can use underscore js _.each to iterate over the object like

_.each(data ,function(product){
    console.log(product.value);
});

see the link: http://underscorejs.org/#each

you can also use for each loop.

Also you can perform filter like below:

_.filter(data, function(product){
    return product.value;
 });
Sign up to request clarification or add additional context in comments.

2 Comments

_.each is vanilla? If not specify what library you are using.
the library is underscore.js, just as @sumit chauhan explains.
0

One other way is to create a dictionary that directly caters to your search.

You can flatten your multi-level key value pair to create a dictionary that you can use readily. The below flatten function (taken from here) creates a dictionary like:

{
  "product.value1": "v1",
  "product.value2": 2
}

You can then just query it using dictionary["product.value1"]

This flatten function can be altered to format the keys like product[value1] if you wish so.

var data = {
    product: {
        value1: 'v1',
        value2: 2
    }
}
var myDictionary = flatten(data);

console.log(myDictionary);
console.log(myDictionary["product.value1"]);
console.log(myDictionary["product.something else"]);


function flatten(obj, opt_out, opt_paths) {
  var out = opt_out || {};
  var paths = opt_paths || [];
  return Object.getOwnPropertyNames(obj).reduce(function(out, key) {
    paths.push(key);
    if (typeof obj[key] === 'object') {
      flatten(obj[key], out, paths);  
    } else {
      out[paths.join('.')] = obj[key];
    }
    paths.pop();
    return out;
  }, out)
}

Comments

0

If you know possible attribute names, then I would define an array with possible attribute names, then iterate over them checking if there is a field with this name

const names = [
  'product',
  'order'
];

function findValue(data){
  if(data.value1) return data.value1;
  for(let name in names){
    if(data[name].value1) return data[name].value1;
  }
}

Comments

0

Explanation

If you want to give your function a string like 'product[value1]' as argument you need to get all attribute values that you need to query for your result value. I did it with query.replace(/(\[)|(\])/g, ' ')split(' '). The returning array you need to check for empty strings and remove them. I did it with filter.
After that you can simply use reduce on the returned array to get on each iteration the new value. In the last iteration you have your result.

Code

function getDataValue(obj, query) {
    var attributes = getAttributeNames(query)
    return attributes.reduce(function(value, current) { 
        return value[current]
    }, obj)
}

function getAttributeNames(query) {
    return query.replace(/(\[)|(\])/g, ' ')
        .split(' ')
        .filter(function(string) {
            return string.length > 0
        })
}

Example

var dataOne = {
    product: {
        value1: 'v1',
        value2: 2
    }
}

var dataTwo = {
    product: {
        subProduct: {
          value1: 'v2'
        }
    }
}

console.log(getDataValue(dataOne, 'product[value1]'))
console.log(getDataValue(dataTwo, 'product[subProduct][value1]'))


function getDataValue(obj, query) {
    var attributes = getAttributeNames(query)
    return attributes.reduce(function(value, current) { 
      return value[current]
    }, obj)
}

function getAttributeNames(query) {
    return query.replace(/(\[)|(\])/g, ' ')
      .split(' ')
      .filter(function(string) {
        return string.length > 0
      })
}

1 Comment

Why don't you directly query.split(/\[|\]/) instead of introducing prone to error spaces ? Object keys can have spaces, and even be only spaces...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.