1

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.

5
  • possible duplicate of How might I extract the property values of a JavaScript object into an array? Commented Jul 28, 2015 at 12:18
  • @FrankvanPuffelen This is not a duplicate of that. I already have that code. I'm looking for it to go deeper and iterate over all levels of the object. The question and answer you link to is doing exactly what I already have working. Commented Jul 28, 2015 at 14:29
  • Close vote retracted, answer below. Commented Jul 28, 2015 at 15:42
  • should the key name indicate the array ordering? e.g.(id1, id2 / thing1 thing2) if so what is the rule? Commented Jul 28, 2015 at 15:49
  • @LukeP the key does not indicate ordering. The object is ordered on the server before being set to the data variable. Commented Jul 28, 2015 at 16:28

3 Answers 3

2

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;
}
Sign up to request clarification or add additional context in comments.

Comments

1

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>

2 Comments

Thanks Frank. Brent's solution and the one I'll select as the answer needs no knowledge of keys.
Sounds good. Keep it mind that both solutions makes an assumption about your data structure (one makes an implicit assumption, the other an explicit one). Such choices are necessary, since you're dealing with a schemaless model so it is not clear from the JSON data itself which level(s) needs to be flattened into an array.
0

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

1 Comment

This doesn't take care of the deeper objects like 'things'.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.