Mapping out JSON structure - javascript

I'm parsing a JSON message which looks something like:
{
staff : [
{name : 'John', department : 'Math'},
{name : 'Sally', department : 'Science'},
],
students : [
{name : 'Bob', department : 'Law'},
{name : 'Lisa', department : 'IT'}
]
}
From which I'd like to pull out an array of each separate value.
i.e.
names -> ['John', 'Sally', 'Bob', 'Lisa']
At the moment I'm doing something like
var names = [];
msg.staff.forEach(function(e) { names.push(e.name) })
msg.students.forEach(function(e) { names.push(e.name)})
This feels overly verbose, just wondering if there's a cleaner way to approach this (for every attribute). I'm already including lodash in this project.

You can use _.pluck to get the value of a property of each object in an array:
_.pluck(obj.staff.concat(obj.students), 'name')

Your instinct is right; you don't need a mutable array to do this with lodash.
_(obj).map().flatten().pluck('name').value();
This version works for any number of array values in o.
JSBin

Edit missed that you had lodash available, will leave this vanilla JS version here anyway.
You could use map to be more concise:
var directory = {
staff : [
{name : 'John', department : 'Math'},
{name : 'Sally', department : 'Science'},
],
students : [
{name : 'Bob', department : 'Law'},
{name : 'Lisa', department : 'IT'}
]
};
var names = directory.staff.concat(directory.students).map(function(person) {
return person.name;
});
If you don't know the individual key names before hand, you could do:
Object.keys(directory).map(function(key) {
return directory[key]
}).reduce(function(p,c){
return p.concat(c)
}).map(function(person) {
return person.name;
});
I didn't catch the requirement of getting an array of all values stored under each key, this should do it though:
Object.keys(directory).map(function(key) {
return directory[key];
}).reduce(function(p,c) {
return p.concat(c);
}).reduce(function(p, c) {
Object.keys(c).forEach(function(oKey) {
if(p[oKey]) p[oKey].push(c[oKey]);
else p[oKey] = [c[oKey]];
});
return p;
}, {});
This returns the following:
{
"name":["John","Sally","Bob","Lisa"],
"department": ["Math","Science","Law","IT"]
}

Related

Merging elements in my SQL query result Array with Javascript [duplicate]

This question already has answers here:
Group by array and add field and sub array in main array
(8 answers)
Closed 1 year ago.
As a newbie, I'm looking for the best approach to achieve the below:
Here is the Array I get from my DB query that contains a left join on the "class" table
[
{"legnumber":1,
"classcode" : "J"},
{"legnumber":1,
"classcode" : "Y"},
{"legnumber":2,
"classcode" : "J"}
]
And I would like to get something like this:
{
"legs": [
{
"legnumber" : 1,
"classes" : [
{"classcode" : "J"},
{"classcode" : "Y"}
]
},
{
"legnumber" : 2,
"classes" : [
{"classcode" : "J"}
]
}
]
}
Thanks a lot for your suggestions.
I'm using Sequelize in this project but I'm writing raw queries as I find it more convenient for my DB model.
Regards,
Nico
Hassan's answer is the more concise way to handle this, but here is a more verbose option to help understand what's happening:
const queryResults = [
{ legnumber: 1, classcode: 'J' },
{ legnumber: 1, classcode: 'Y' },
{ legnumber: 2, classcode: 'J' },
]
// create an object to store the transformed results
const transformedResults = {
legs: [],
}
// loop through each item in the queryResult array
for (const result of queryResults) {
// try to find an existing leg tha matches the current leg number
let leg = transformedResults.legs.find((leg) => leg.legnumber === result.legnumber)
// if it doesn't exist then create it and add it to the transformed results
if (!leg) {
leg = {
legnumber: result.legnumber,
classes: [],
}
transformedResults.legs.push(leg)
}
// push the classcode
leg.classes.push({ classcode: result.classcode })
}
console.log(transformedResults)
You can group your array items based on legnumber using array#reduce and then get all the values to create your result using Object.values().
const arr = [ {"legnumber":1, "classcode" : "J"}, {"legnumber":1, "classcode" : "Y"}, {"legnumber":2, "classcode" : "J"} ],
output = arr.reduce((r, {legnumber, classcode}) => {
r[legnumber] ??= {legnumber, classes: []};
r[legnumber].classes.push({classcode});
return r;
},{}),
result = {legs: Object.values(output)};
console.log(result);

Javascript push array column to an one dimention array

I would like to push the age attribute from items to an ages array
f.e.
items =[{name : "asd", age : "23"},
{name : "asd2", age : "34"}]
to an array:
ages = [ 23,34]
If you got it right then you can use .map to get all the values corresponding to key age.
var items =[{name: "asd", age: "23"}, {name: "asd2", age: "34"}];
var data = items.map(({age}) => age);
console.log(data);

lodash collection - add extra custom property in existing objects of collection

This is my first time using lodash and I'm trying to figure out how to update each record within a JSON object. For example, let's say I have a person object:
"person":[
{
"firstName" : "Alex",
"lastName" : "Smith"
},
{
"firstName" : "Madison",
"lastName" : "Matthews"
}
]
I would like to add a new field called "fullName" to each record in person that is a combination of their first and last names. Is there a way I can do this using lodash and/or javascript? I don't want to use any other tool.
Thanks!
Here if you have persons collection(Array of json objects) then you can add one more property by traversing the collection with lodash function. There are other several ways also.
var persons = [
{
"firstName" : "Alex",
"lastName" : "Smith"
},
{
"firstName" : "Madison",
"lastName" : "Matthews"
}
];
var personsWithFullName = _(persons).forEach(function(person) {
person.fullName = person.firstName + person.lastName;
return person;
});
or
var newPersonsWithFullName = _.map(persons , function(person) {
return _.assign({}, person, {fullName: (person.firstName + person.lastName)});
});

Javascript, deep extend

So I have an object I'm trynig to deep extend into - right now the extend function works if the lowest level is just an array, So it looks like this :
function(base, next) {
var dataEntry = base.filter(function(it) {
return it.module === next.module;
})[0];
if (dataEntry) {
var diff = next.customUrl.filter(function(it) {
return dataEntry.customUrl.indexOf(it) === -1;
});
dataEntry.customUrl = dataEntry.customUrl.concat(diff).sort();
//_.extend(dataEntry, next);
} else {
base.push(next);
}
}
And this works if the object looks like :
[
{"name" : "one", "test" : ["1","2"]},
{"name" : "two", "test" : ["1","2"]}
]
However some things had to change and now the object looks like this :
[
{"name" : "one", "test" : [{"random1" : true},{"random2" : false}] },
{"name" : "two", "test" : [{"random3" : true},{"random4" : false}]}
]
Where the keys in the array is now an array of objects, and the objects keys are random. So If there was an object with the same key - replace the value (unless its the same, otherwise push a new object inside of there.
So for that object above I would pass this to merge into it for example:
{"name" : "one", "test" : [{"random2" : true}]}
So that would change the value of random2 to true, or something like this
{"name" : "one", "test" : [{"random18" : true}] }
where that would push in random 18 like so :
[
{"name" : "one", "test" : [{"random1" : true},{"random2" : false},{"random18" : true}] },
{"name" : "two", "test" : [{"random3" : true},{"random4" : false}]}
]
Unsure how to traverse deeper and merge. Thanks for reading!!
Edit : first stab at it -
function(base, next) {
var dataEntry = base.filter(function(it) {
return it.module === next.module;
})[0];
if (dataEntry) {
var allTags = [];
allTags.push.apply(allTags, dataEntry.customUrl);
allTags.push.apply(allTags, next.customUrl);
dataEntry.customUrl = allTags;
} else {
base.push(next);
}
}
Does not work because it does not cover over objects if they are the same, just pushes into array.
http://jsfiddle.net/p08ayvv8/
this fiddle shows you how jQuery can deal with (deep) extending objects.
See http://api.jquery.com/jquery.extend/ for a detailed explaination.
It is mentionable though that when preforming the second extension jQuery will prepend the old value of test to the array, thats why I added
o1.test = o1.test[0];

Find duplicates in nested object

Assuming that I have a JS object wich contains other objects inside it, but all of them have the same structure.
I am trying to search inside them for any duplicated values.
For example:
{
{
id: "123"
name: "John"
surname: "Smith"
phone: "123456789"
},
{
id: "456"
name: "Jack"
surname: "Jones"
phone: "9876789123"
},
{
id: "789"
name: "John"
surname: "Doe"
phone: "123456789"
}
}
I want to search and find that the property 'phone' with value '123456789' is the same on both objects with ids '123' and '789'.
Note: the property/value combination that I am searching for is unknown beforehand.
First, if the outer structure is a plain Object, use an Array instead. If you can't change the structure, I'd convert it first.
DEMO: http://jsfiddle.net/3Y2qr/
if (!Array.isArray(data))
data = Object.keys(data)
.sort(function(a,b) { return a - b })
.map(function(key) { return data[key] })
Then you can reduce the set to groups of matches.
var groupByPhone = data.reduce(function(found, obj) {
if (found[obj.phone])
found[obj.phone].push(obj)
else
found[obj.phone] = [obj]
return found
}, {});
var dupes = Object.keys(groupByPhone)
.filter(function(key) {
return groupByPhone[key].length > 1
})
So now groupByPhone is an object where the keys are the unique phone numbers, and the values are the objects that have that number.
The dupes will be a list of phone number keys that can be used to lookup groups of duplicate objects in groupByPhone.
Array.prototype.filter to the rescue !
var searchFor = '123456789';
var filteredResult = arrayOfObjects.filter(function( obj ) {
return obj.phone === searchFor;
});
console.log( filteredResult );

Categories