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.
-
possible duplicate of How might I extract the property values of a JavaScript object into an array?Frank van Puffelen– Frank van Puffelen2015年07月28日 12:18:09 +00:00Commented 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.Mark Garrigan– Mark Garrigan2015年07月28日 14:29:58 +00:00Commented Jul 28, 2015 at 14:29
-
Close vote retracted, answer below.Frank van Puffelen– Frank van Puffelen2015年07月28日 15:42:03 +00:00Commented 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?Luke– Luke2015年07月28日 15:49:16 +00:00Commented 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.Mark Garrigan– Mark Garrigan2015年07月28日 16:28:13 +00:00Commented Jul 28, 2015 at 16:28
3 Answers 3
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;
}
Comments
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
var newData = [];
var dataKeys = Object.keys(data);
for(var i=0; i<dataKeys.length; i++)
{
newData.push(data[dataKeys[i]]);
}