'flatten nested object using lodash

flatten, flattenDeep or flattenDepth of lodash only accept array. How to flatten nested object?

var data = {
  "dates": {
    "expiry_date": "30 sep 2018",
    "available": "30 sep 2017",
    "min_contract_period": [{
      "id": 1,
      "name": "1 month",
      "value": false
    }, {
      "id": 2,
      "name": "2 months",
      "value": true
    }, {
      "id": 3,
      "name": "3 months",
      "value": false
    }]
  },
  "price": {
    "curreny": "RM",
    "min": 1500,
    "max": 2000
  }
}

I want nested property to be the first level, like expiry_date should be level 1, not within dates, and I think dates should be gone, it's not needed anymore. I can do it manually, use map() but I'm looking to use lodash to ease the task.



Solution 1:[1]

One of the easiest solutions would be, merging the nested object with parent,

_.merge(data, data.dates);

This will bring all data.dates property into data. Then delete data.dates

delete data.dates

Solution 2:[2]

ES6 version:

var data = {
  "dates": {
    "expiry_date": "30 sep 2018",
    "available": "30 sep 2017",
    "min_contract_period": [{
      "id": 1,
      "name": "1 month",
      "value": false
    }, {
      "id": 2,
      "name": "2 months",
      "value": true
    }, {
      "id": 3,
      "name": "3 months",
      "value": false
    }]
  },
  "price": {
    "curreny": "RM",
    "min": 1500,
    "max": 2000
  }
};

var {dates: {expiry_date, ...dates}, ...rest} = data;
var flatData = {dates, expiry_date, ...rest}
console.log(flatData)

One thing to note is that you have to be careful with deeply nested destructuting. In this example if data.dates is undefined and you'll try to destructure it, error will be thrown.

Solution 3:[3]

You can .merge() the result of .get() and _.pick():

var data = {"dates": {"expiry_date": "30 sep 2018","available": "30 sep 2017","min_contract_period": [{"id": 1,"name": "1 month","value": false}, {"id": 2,"name": "2 months","value": true}, {"id": 3,"name": "3 months","value": false}]},"price": {"curreny": "RM","min": 1500,"max": 2000}},
    result = _.merge(_.get(data, 'dates'), _.pick(data, 'price'));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Solution 4:[4]

From Andrey's answer

function flattenObject(o, prefix = '', result = {}, keepNull = true) {
  if (_.isString(o) || _.isNumber(o) || _.isBoolean(o) || (keepNull && _.isNull(o))) {
    result[prefix] = o;
    return result;
  }

  if (_.isArray(o) || _.isPlainObject(o)) {
    for (let i in o) {
      let pref = prefix;
      if (_.isArray(o)) {
        pref = pref + `[${i}]`;
      } else {
        if (_.isEmpty(prefix)) {
          pref = i;
        } else {
          pref = prefix + '.' + i;
        }
      }
      flattenObject(o[i], pref, result, keepNull);
    }
    return result;
  }
  return result;
}

Solution 5:[5]

this flattens object with nested objects and arrays of any depth. keys in resulting object are full paths to properties in input object

public static flattenObject(o: any, prefix?: string, result?: any): any {

    prefix = prefix ? prefix : '';
    result = result ? result : {};

    if (_.isString(o) || _.isNumber(o) || _.isBoolean(o)) {
        result[prefix] = o;
        return result;
    }

    if (_.isArray(o) || _.isPlainObject(o)) {
        for (let i in o) {

            let pref = prefix;
            if (_.isArray(o)) {
                pref = pref + `[${i}]`;
            } else {
                if (_.isEmpty(prefix)) {
                    pref = i;
                } else {
                    pref = prefix + '.' + i;
                }
            }

            Utils.flattenObject(o[i], pref, result);
        }
        return result;
    }


    return result;
}

Solution 6:[6]

If you need to flatten the whole object, not only its "dates" property, something like this should work, you don't even need lodash:

function flattenObject(obj) {
  const result = {};

  Object.values(obj).forEach(nestedObject => {
    Object.assign(result, nestedObject);
  });

  return result;
}

Solution 7:[7]

If you're looking for an existing solution you can use a library called flat, as it said in this issue

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 RaR
Solution 2
Solution 3
Solution 4
Solution 5 Andrey
Solution 6 Alexey Grinko
Solution 7 ilyavysotski