I'm struggling with converting the nested JSON array that I have.
{
"Id": "1234",
"Company": {
"element": [{
"Name": "htc",
"Contacts": {
"element": [{
"name": "john",
"phone": "1234"
}, {
"name": "peter",
"phone": "5678"
}]
},
"Address": {
"element": {
"country": "us",
"state": "cali"
}
}
}, {
"Name": "samsung",
"Contacts": {
"element": [{
"name": "luke",
"phone": "0011"
}, {
"name": "james",
"phone": "2233"
}]
},
"Address": {
"element": {
"country": "us",
"state": "texas"
}
}
}]
}
}
As you'll notice, there's this "element" in the arrays "Company", "Contacts" and "Address". But the output that I need to provide should not contain the "element" such as this code:
{
"Id": "1234",
"Company": [{
"Name": "htc",
"Contacts": [{
"name": "john",
"phone": "1234"
}, {
"name": "peter",
"phone": "5678"
}],
"Address": [{
"country": "us",
"state": "cali"
}]
}, {
"Name": "samsung",
"Contacts": [{
"name": "luke",
"phone": "0011"
}, {
"name": "james",
"phone": "2233"
}],
"Address": [{
"country": "us",
"state": "texas"
}]
}]
}
I have no clue how to do in JavaScript. Any ideas/tips are appreciate.
Thank you
You can try something like this:
var data={Id:"1234",Company:{element:[{Name:"htc",Contacts:{element:[{name:"john",phone:"1234"},{name:"peter",phone:"5678"}]},Address:{element:{country:"us",state:"cali"}}},{Name:"samsung",Contacts:{element:[{name:"luke",phone:"0011"},{name:"james",phone:"2233"}]},Address:{element:{country:"us",state:"texas"}}}]}};
var keysToClean = ["Address", "Contacts"]
// Copy object instead of reference
var result = Object.assign({}, data);
result.Company = result.Company.element;
result.Company.forEach(x => {
keysToClean.forEach(k => {
x[k] = Array.isArray(x[k]) ? x[k].element : [x[k].element]
})
})
console.log(result);
Note: I have use Object.create and Arrow functions. They are not supported by old browsers. You can refer to following link for alternative to deep copy an object:
What is the most efficient way to deep clone an object in JavaScript?
The solution using Array.prototype.forEach() function:
var companyData = { "Id": "1234", "Company": { "element": [{ "Name": "htc", "Contacts": { "element": [{ "name": "john", "phone": "1234" }, { "name": "peter", "phone": "5678" }] }, "Address": { "element": { "country": "us", "state": "cali" } } }, { "Name": "samsung", "Contacts": { "element": [{ "name": "luke", "phone": "0011" }, { "name": "james", "phone": "2233" }] }, "Address": { "element": { "country": "us", "state": "texas" } } }] }
};
companyData.Company = companyData.Company.element;
var omitElement = function(o){
if (!o['element']) return o;
return (Array.isArray(o.element))? o.element : [o.element];
}
companyData.Company.forEach(function (o) {
o.Contacts = omitElement(o.Contacts);
o.Address = omitElement(o.Address);
});
console.log(companyData);
Please see this Plunker This should help.. it will generate desired result you need but be aware this is just a way to do this, and only meant for information purpose. It's not production grade...
function ParseData(data)
{
var newObject={Id:0, Company:[]};
newObject["Id"]=data["Id"];
newObject["Company"]=CreateCompanyObject(data["Company"]["element"]);
console.log(JSON.stringify(newObject));
}
function CreateCompanyObject(data)
{
var companies=[];
for(var i=0;i<data.length;i++)
{
companies.push({
name:data[i].Name,
contacts:CreateContactObject(data[i].Contacts.element),
Address:CreateAddressObject(data[i].Address.element)});
};
return companies;
}
function CreateContactObject(data){
var contacts=[];
for(var i=0;i<data.length;i++)
contacts.push(data[i]);
return contacts;
}
function CreateAddressObject(data){
var address=[];
if(typeof(data)=="array"){
for(var i=0;i<data.length;i++)
address.push(data[i]);
}
else
address.push(data);
return address;
}
You could check for element and move the content a step ahead to its parent.
function deleteElement(object){
Object.keys(object).forEach(function (k) {
if (object[k] && typeof object[k] === 'object') {
if ('element' in object[k]) {
object[k] = Array.isArray(object[k].element) ?
object[k].element :
[object[k].element];
}
deleteElement(object[k]);
}
});
}
var data = { Id: "1234", Company: { element: [{ Name: "htc", Contacts: { element: [{ name: "john", phone: "1234" }, { name: "peter", phone: "5678" }] }, Address: { element: { country: "us", state: "cali" } } }, { Name: "samsung", Contacts: { element: [{ name: "luke", phone: "0011" }, { name: "james", phone: "2233" }] }, Address: { element: { country: "us", state: "texas" } } }] } };
deleteElement(data);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I'm trying to search through a JSON object to find the pet-rock that I want to delete. Here is a simple JSON that I'm working on:
myData.json:
{
"data": [
{
"name": "John",
"age": "25",
"pet-rocks": [
{
"name": "Travis",
"age": "9"
},
{
"name": "Steven",
"age": "5"
},
{
"name": "Oliver",
"age": "7"
}
]
},
{
"name": "Jane",
"age": "25",
"pet-rocks": [
{
"name": "Jesse",
"age": "4"
},
{
"name": "Carol",
"age": "8"
},
{
"name": "Jake",
"age": "7"
}
]
}
]
}
I would like to do a search for "Steven" and remove that pet-rock from the list. Here are the things I've tried:
MyJSFile.js:
const myDataObject = require('./myData.json');
for (let key in myDataObject) {
let value = myDataObject[key];
if (value === "Steven")
{
delete myDataObject[key];
}
//To see if I get the data I want
console.log(key, value);
}
However, my output is strange and I'm not sure how to get to that child node of petrock. It appears that the petrocks are in object form, and I'm not sure how to get to them. here is the ouput of my console below. I assume it didn't get delete as there are still 3 petrock objects in the data.
data [
{
name: 'Robert',
age: '25',
'pet-rocks': [ [Object], [Object], [Object] ]
},
{
name: 'Robert',
age: '25',
'pet-rocks': [ [Object], [Object], [Object] ]
}
]
Any help or suggestions would be greatly appreciated! Thanks!
The pet rock named Steven is not a direct child of myDataObject, so you can't delete it like that. You can loop through the "data" array, rebuilding the "pet-rocks" array for each element. A simple filter to remove any pet rocks named Steven should work.
const myDataObject = {
"data": [
{
"name": "John",
"age": "25",
"pet-rocks": [
{
"name": "Travis",
"age": "9"
},
{
"name": "Steven",
"age": "5"
},
{
"name": "Oliver",
"age": "7"
}
]
},
{
"name": "Jane",
"age": "25",
"pet-rocks": [
{
"name": "Jesse",
"age": "4"
},
{
"name": "Carol",
"age": "8"
},
{
"name": "Jake",
"age": "7"
}
]
}
]
};
myDataObject.data.forEach(d => {
d["pet-rocks"] = d["pet-rocks"].filter(rock => rock.name !== "Steven");
});
console.log(myDataObject);
I have the following flat array:
{ "State": "New York", "Name": "Jane", "Product": "Apple" },
{ "State": "New York", "Name": "Jill", "Product": "Banana"},
{ "State": "California", "Name": "Jill", "Product": "Apple" },
{ "State": "California", "Name": "Jill", "Product": "Banana"}
Is it possible to create a 2-level nested array (i.e., Name > nested State Array > nested Product Array)? It would look like as follows:
{
"Name": "Jill",
"States": [
{
"State": "California",
"Products": [
{
"Product": "Apple"
},
{
"Product": "Banana"
}
]
},
{
"State": "New York",
"Products": [
{
"Product": "Banana"
}
]
}
]
},
{
"Name": "Jane",
"States": [
{
"State": "New York",
"Products": [
{
"Product": "Apple"
}
]
}
]
}
I have been able to get one level nested (States). How would you nest the second level?
Here is a stackblitz: https://stackblitz.com/edit/angular-lu6zj2
this.grouped_data = this.data.reduce((data, item) => {
data[item.Name] = data[item.Name] || { Name: item.Name, States: []}
data[item.Name].States.push(item)
return data;
}, {})
let data = [
{ "State": "New York", "Name": "Jane", "Product": "Apple" },
{ "State": "New York", "Name": "Jill", "Product": "Banana"},
{ "State": "California", "Name": "Jill", "Product": "Apple" },
{ "State": "California", "Name": "Jill", "Product": "Banana"}
];
let grouped = data.reduce((p, n) => {
// Create the Lady
if (!p[n.Name]) p[n.Name] = { States: [] };
// Check if the state exists, if not create it, then push product into it
if (!p[n.Name].States.some(state => state.State === n.State)) {
p[n.Name].States.push({ State: n.State, Products: [n.Product] });
} else {
!p[n.Name].States.find(state => state.State === n.State).Products.push(n.Product);
}
return p;
}, {});
console.log(grouped);
After that you can also remove duplicated products if you want to. I'll let you deal with it !
EDIT I didn't respect your model, what a dumbass am I ... Here it is :
let data = [
{ "State": "New York", "Name": "Jane", "Product": "Apple" },
{ "State": "New York", "Name": "Jill", "Product": "Banana"},
{ "State": "California", "Name": "Jill", "Product": "Apple" },
{ "State": "California", "Name": "Jill", "Product": "Banana"}
];
let grouped = data.reduce((p, n) => {
// Create the Lady
if (!p.some(lady => lady.Name === n.Name)) p.push({ Name: n.Name, States: [] });
let lady = p.find(lady => lady.Name === n.Name);
// Check if the state exists, if not create it, then push product into it
if (!lady.States.some(state => state.State === n.State)) {
lady.States.push({ State: n.State, Products: [n.Product] });
} else {
lady.States.find(state => state.State === n.State).Products.push(n.Product);
}
return p;
}, []);
console.log(grouped);
I search how to sort by place.city this kind of object who have id's for keys. The need is to keep id's for first keys…
{
"123": {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "Bob",
"age": 45
}
},
"456": {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Louis",
"age": 34
}
},
"789": {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Kevin",
"age": 27
}
}
}
I try some kind of function like this and the expected result is not here.
let result = _(myObject).map(function (value, key) {
return _.defaults({ name: key }, value)
}).sortBy('city').value()
You can't sort an object.. You can, however, convert your object to an array and sort that.
var data ={
"123" : {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "Bob",
"age": 45
}
},
"456" : {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Louis",
"age": 34
}
},
"789" : {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Kevin",
"age": 27
}
}
};
var sortedByPlace = _.sortBy(Object.keys(data).map(k => ({id:k, ...data[k]})), (d)=> d.place.city)
console.log(sortedByPlace);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
It is not possible to sort an object, you need to make it a list.
import { map, flow } from 'lodash'
import { sortBy } from 'lodash/fp'
cities => flow(
map(places, (place, id) => { id, ...place }),
sortBy('city'),
)()
Your second question begs the question (mh...) if you want local sort. That would be
import { mapValues } from 'lodash'
import { sortBy } from 'lodash/fp'
data => mapValues(data, sortBy('place.city'))
You cant sort an object. However you could create a sorted array that contains references to the objects:
const sorted = Object.values(myObject).sort((a, b) => a.place.city.localeCompare(b.place.city));
If you look at this answer, the following should work
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
sort("place.city", myObject);
I realize the object I have to treat (get from an obscur API) is a little bit more complicated than my first example :/
So the responses you nicely give are not working anymore…
Do you see the subtlety on this new object ?
The point stay to sort by place.city
{
"123": {
0: {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "Bob",
"age": 45
}
},
1: {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "James",
"age": 32
}
}
},
"456": {
0: {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Louis",
"age": 34
}
},
1: {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Christine",
"age": 65
}
}
},
"789": {
0: {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Kevin",
"age": 27
}
},
1: {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Robert",
"age": 55
}
},
2: {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Danny",
"age": 62
}
}
}
}
I want to group JSON by First char of first name but the resultant object should have two attributes "Key" & "Data"
I tried using lodash which has given me partial expected result but not the complete.
Following are the details with data, expected result, current result and current code implemented using lodash.
Any help will be appreciated.
JSON:
UserData = [
{
"gender":"male",
"name":{
"title":"mr",
"first":"landon",
"last":"gonzalez",
},
"location":{
"street":"7927 bollinger rd",
"city":"madison",
"state":"washington",
"postcode":24642
},
"email":"landon.gonzalez#example.com",
"dob":"1972-04-26 11:40:09",
"registered":"2013-07-04 17:42:44",
"phone":"(038)-931-4026",
"cell":"(808)-824-5320",
"nat":"US"
},
{
"gender":"male",
"title":"mr",
"first_name":"jonathan",
"last_name":"petersen",
"location":{
"street":"2583 brorsonsvej",
"city":"brøndby strand",
"state":"hovedstaden",
"postcode":87814
},
"email":"jonathan.petersen#example.com",
"dob":"1948-05-06 21:48:27",
"registered":"2009-03-09 17:04:40",
"phone":"03441612",
"cell":"73824887",
"nat":"DK"
},
{
"gender":"male",
"name":{
"title":"mr",
"first":"roméo",
"last":"marchand",
},
"location":{
"street":"9471 rue bony",
"city":"créteil",
"state":"maine-et-loire",
"postcode":30698
},
"email":"roméo.marchand#example.com",
"dob":"1969-08-18 16:41:01",
"registered":"2015-04-21 19:26:04",
"phone":"04-43-18-74-25",
"cell":"06-83-89-77-72",
"nat":"FR"
}
]
Expected:
[
{ key: 'A', data: [{...}, {...}, {...}] },
{ key: 'B', data: [{...}, {...}, {...}] },
{ key: 'C', data: [{...}, {...}, {...}] },
]
Current:
[
{ 'A': [{...}, {...}, {...}] },
{ 'B': [{...}, {...}, {...}] },
{ 'C': [{...}, {...}, {...}] },
]
Current Code:
sectionListData(users){
let sectionedUsers = _.groupBy(users, function(user) {
return user.first_name.charAt(0).toUpperCase();
});
alert(JSON.stringify(sectionedUsers));
}
Use lodash.chain and after grouping, map the results to create objects of your choice:
let UserData = [{
"gender": "male",
"name": {
"title": "mr",
"first": "landon",
"last": "gonzalez",
},
"location": {
"street": "7927 bollinger rd",
"city": "madison",
"state": "washington",
"postcode": 24642
},
"email": "landon.gonzalez#example.com",
"dob": "1972-04-26 11:40:09",
"registered": "2013-07-04 17:42:44",
"phone": "(038)-931-4026",
"cell": "(808)-824-5320",
"nat": "US"
},
{
"gender": "male",
"title": "mr",
"first_name": "jonathan",
"last_name": "petersen",
"location": {
"street": "2583 brorsonsvej",
"city": "brøndby strand",
"state": "hovedstaden",
"postcode": 87814
},
"email": "jonathan.petersen#example.com",
"dob": "1948-05-06 21:48:27",
"registered": "2009-03-09 17:04:40",
"phone": "03441612",
"cell": "73824887",
"nat": "DK"
},
{
"gender": "male",
"name": {
"title": "mr",
"first": "roméo",
"last": "marchand",
},
"location": {
"street": "9471 rue bony",
"city": "créteil",
"state": "maine-et-loire",
"postcode": 30698
},
"email": "roméo.marchand#example.com",
"dob": "1969-08-18 16:41:01",
"registered": "2015-04-21 19:26:04",
"phone": "04-43-18-74-25",
"cell": "06-83-89-77-72",
"nat": "FR"
}
];
let sectionedUsers = _.chain(UserData)
.groupBy(function(user) {
let firstName = _.get(user, 'name.first') || user.first_name;
return firstName.charAt(0).toUpperCase();
})
.map((data, key) => ({
key,
data
}))
.value();
console.log(sectionedUsers);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
You could _.map the grouped result.
var userData = [{ gender: "male", name: { title: "mr", first: "landon", last: "gonzalez" }, location: { street: "7927 bollinger rd", city: "madison", state: "washington", postcode: 24642 }, email: "landon.gonzalez#example.com", dob: "1972-04-26 11:40:09", registered: "2013-07-04 17:42:44", phone: "(038)-931-4026", cell: "(808)-824-5320", nat: "US" }, { gender: "male", title: "mr", name: { first: "jonathan", last: "petersen" }, location: { street: "2583 brorsonsvej", city: "brøndby strand", state: "hovedstaden", postcode: 87814 }, email: "jonathan.petersen#example.com", dob: "1948-05-06 21:48:27", registered: "2009-03-09 17:04:40", phone: "03441612", cell: "73824887", nat: "DK" }, { gender: "male", name: { title: "mr", first: "roméo", last: "marchand" }, location: { street: "9471 rue bony", city: "créteil", state: "maine-et-loire", postcode: 30698 }, email: "roméo.marchand#example.com", dob: "1969-08-18 16:41:01", registered: "2015-04-21 19:26:04", phone: "04-43-18-74-25", cell: "06-83-89-77-72", nat: "FR" }];
let sectionedUsers = _(userData)
.groupBy(user => user.name.first[0].toUpperCase())
.map((data, key) => ({ key, data }))
.value();
console.log(sectionedUsers);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
I have the following JavaScript object
[
{
"familyName": "Smith",
"children": [
{ "firstName": "John" },
{ "firstName": "Mike" }
]
},
{
"familyName": "Williams",
"children": [
{ "firstName": "Mark" },
{ "firstName": "Dave" }
]
},
{
"familyName": "Jones",
"children": [
{ "firstName": "Mary" },
{ "firstName": "Sue" }
]
}
]
I’d like to create an array of all children i.e.
[
{ "FirstName": "John" },
{ "FirstName": "Mike" },
{ "FirstName": "Mark" },
{ "FirstName": "Dave" },
{ "FirstName": "Mary" },
{ "FirstName": "Sue" }
]
I am using jQuery.
I have looked at posts that describe merging or concatenating arrays but not those of child arrays: e.g. Merge/flatten an array of arrays in JavaScript?
I believe I could loop through the families and add the children arrays but suspect that there is a 'one-liner' for this?
I tested in the console:
//The families(duh)
const families = [
{
"familyName": "Smith",
"children": [
{ "firstName": "John" },
{ "firstName": "Mike" }
]
},
{
"familyName": "Williams",
"children": [
{ "firstName": "Mark" },
{ "firstName": "Dave" }
]
},
{
"familyName": "Jones",
"children": [
{ "firstName": "Mary" },
{ "firstName": "Sue" }
]
}
]
//Just flatten the children:
var children = [].concat.apply([], families.map(family => family.children));
//Outputs
console.log(children);
A solution without jQuery would be to use reduce to extract children from their families (sounds a bit rough, sorry for that).
families.reduce(function(list, family){
return list.concat(family.children);
}, []);
You can do this by using $.map:
var a = [
{
"familyName": "Smith",
"children": [
{ "firstName": "John" },
{ "firstName": "Mike" }
]
},
{
"familyName": "Williams",
"children": [
{ "firstName": "Mark" },
{ "firstName": "Dave" }
]
},
{
"familyName": "Jones",
"children": [
{ "firstName": "Mary" },
{ "firstName": "Sue" }
]
}
]
console.log($.map(a, function(it){
return it.children;
}));
// Or ES6
$.map(a, it => it.children);
Result:
[
{
"firstName":"John"
},
{
"firstName":"Mike"
},
{
"firstName":"Mark"
},
{
"firstName":"Dave"
},
{
"firstName":"Mary"
},
{
"firstName":"Sue"
}
]
Try with Array#forEach method .then push the children object with new array
var families = [ { "familyName": "Smith", "children": [ { "firstName": "John" }, { "firstName": "Mike" } ] }, { "familyName": "Williams", "children": [ { "firstName": "Mark" }, { "firstName": "Dave" } ] }, { "familyName": "Jones", "children": [ { "firstName": "Mary" }, { "firstName": "Sue" } ] } ]
var children = [];
families.forEach(family => family.children.forEach(child => children.push(child)));
console.log(children);