Mark Garrigan
Mark Garrigan

Reputation: 13

Creating Arrays of Objects in nested Objects with Javascript

Given the following javascript object structure, which is typically what is returned by firebase

var data = {
  'id1' : {
    'fname' : 'value',
    'lname' : 'value',
    'things' : {
      'thing1' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing2' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing3' : {
        'brand' : 'value',
        'name' : 'value'
      }
    }
  },
  'id2' : {
    'fname' : 'value',
    'lname' : 'value',
    'things' : {
      'thing1' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing2' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing3' : {
        'brand' : 'value',
        'name' : 'value'
      }
    }
  }
};

How would you convert it to

[
  {
    'fname' : 'value',
    'lname' : 'value,
    'things' : [
      {
        'brand' : 'value',
        'name' : 'value'
      },
      {
        'brand' : 'value',
        'name' : 'value'
      },
      {
        'brand' : 'value',
        'name' : 'value'
      }
    ]
  },
  {
    'fname' : 'value',
    'lname' : 'value,
    'things' : [
      {
        'brand' : 'value',
        'name' : 'value'
      },
      {
        'brand' : 'value',
        'name' : 'value'
      },
      {
        'brand' : 'value',
        'name' : 'value'
      }
    ]
  }
]

Keeping in mind that the nested objects could get deeper than this. There are many implementations to convert nested structures to arrays, but I have not seen anyone make this specific conversion. I've been racking my brain for a while and have only come very close but have yet to get it just right.

I already have this code which doesn't do anything with deeper objects like 'things'.

var collection = [];
for(key in data) {
  collection.push(data[key]);
}

I'm struggling with making it recursive.

EDIT I would imagine it needs to be in wrapped in a function that can call itself so that it can be made recursive.

Upvotes: 1

Views: 132

Answers (3)

Brent Hagany
Brent Hagany

Reputation: 36

Here's a solution that doesn't require knowing the keys, assuming that you want to convert every other level of nesting:

function toArrayOfObjects(obj) {
  var collection = [];
  for (key in obj) {
    var value = obj[key];
    if (typeof value === 'object' && !Array.isArray(value)) {
      var childObj = {};
      for (childKey in value) {
        var childValue = value[childKey];
        if (typeof childValue === 'object' && !Array.isArray(childValue)) {
          childObj[childKey] = toArrayOfObjects(childValue);
        } else {
          childObj[childKey] = childValue;
        }
      }
      collection.push(childObj);
    } else {
      collection.push(value);
    }
  }
  return collection;
}

Upvotes: 2

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

Something like this should do the trick:

function convert(object, propNamesToConvert) {
  var array = [];
  Object.keys(object).forEach(function(key) {
    array.push(visit(object[key], propNamesToConvert));
  });
  return array;
}

function visit(object, propNamesToConvert) {
  var result = {};
  Object.keys(object).forEach(function(key) {
    var value = object[key];
    if (typeof(value) === 'object') {
      // objects are either 'things to be converted' or we need to traverse further down the rabbit hole
      if (propNamesToConvert.indexOf(key) >= 0) {
        value = convert(value, propNamesToConvert);
      }
      else {
        value = visit(value, propNamesToConvert);
      }
    }
    result[key] = value;
  });
  return result;
}

console.log(JSON.stringify(visit(data, ['things'])));

It could probably be shortened considerably, but this works. It would be way better to translate the hard-coded ['things'] into something that is less maintenance-prone.

var data = {
  'id1' : {
    'fname' : 'value',
    'lname' : 'value',
    'things' : {
      'thing1' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing2' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing3' : {
        'brand' : 'value',
        'name' : 'value'
      }
    }
  },
  'id2' : {
    'fname' : 'value',
    'lname' : 'value',
    'things' : {
      'thing1' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing2' : {
        'brand' : 'value',
        'name' : 'value'
      },
      'thing3' : {
        'brand' : 'value',
        'name' : 'value'
      }
    }
  }
};

function convert(object, propNamesToConvert) {
  var array = [];
  Object.keys(object).forEach(function(key) {
    array.push(visit(object[key], propNamesToConvert));
  });
  return array;
}

function visit(object, propNamesToConvert) {
  var result = {};
  Object.keys(object).forEach(function(key) {
    var value = object[key];
    if (typeof(value) === 'object') {
      if (propNamesToConvert.indexOf(key) >= 0) {
        value = convert(value, propNamesToConvert);
      }
      else {
        value = visit(value, propNamesToConvert);
      }
    }
    result[key] = value;
  });
  return result;
}

console.log(JSON.stringify(visit(data, ['things'])));
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>

Upvotes: 1

Peter Peng
Peter Peng

Reputation: 1958

var newData = [];
var dataKeys = Object.keys(data);
for(var i=0; i<dataKeys.length; i++)
{
    newData.push(data[dataKeys[i]]);
}

Upvotes: 0

Related Questions