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>
Related
I am looking to solve 2 problems here
Group the orders to create an items array based on based on orderNo
Include the tracking-information from the tracking array in tracking.json into the orders array.
So far I have only managed to get started with the grouping.
//orders.json
const orders = [
{
"orderNo": "1",
"tracking_number": "001",
"courier": "FedEx",
"street": "1745 T Street Southeast",
"zip_code": 20020,
"city": "Louisville",
"destination_country": "USA",
"email": "test#test.com",
"articleNo": "A",
"articleImageUrl": "watch.jpg",
"quantity": 1,
"product_name": "Watch"
},
{
"orderNo": "1",
"tracking_number": "001",
"courier": "FedEx",
"street": "1745 T Street Southeast",
"zip_code": 20020,
"city": "Louisville",
"destination_country": "USA",
"email": "test#test.com",
"articleNo": "B",
"articleImageUrl": "belt.jpg",
"quantity": 2,
"product_name": "Belt"
},
{
"orderNo": "2",
"tracking_number": "002",
"courier": "FedEx",
"street": "637 Britannia Drive",
"zip_code": 94591,
"city": "Vallejo",
"destination_country": "USA",
"email": "test#test.com",
"articleNo": "",
"articleImageUrl": "",
"quantity": "",
"product_name": ""
}
];
//tracking.json
const tracking = [{
"tracking_number": "001",
"location": "",
"timestamp": "2018-04-01T00:00:00.000Z",
"status": "OrderProcessed",
"status_text": "Order processed",
"status_details": "The order has been processed."
},
{
"tracking_number": "002",
"location": "",
"timestamp": "2018-04-06T05:58:00.000Z",
"status": "OrderProcessed",
"status_text": "Order processed",
"status_details": "The order has been processed."
}
]
//expected output data.json
const data = [
{
"orderNo":"1",
"tracking_number":"001",
"courier":"FedEx",
"street":"1745 T Street Southeast",
"zip_code":"20020",
"city":"Louisville",
"destination_country":"USA",
"email":"test#test.com",
"articleNo":"A",
"articleImageUrl":"watch.jpg",
"quantity":"1",
"product_name":"Watch",
"items":[
{
"articleNo":"A",
"articleImageUrl":"watch.jpg",
"quantity":"1",
"product_name":"Watch"
},
{
"articleNo":"B",
"articleImageUrl":"belt.jpg",
"quantity":"2",
"product_name":"Belt"
}
],
"tracking":{
"tracking_number":"001",
"location":null,
"timestamp":"2018-04-01T00:00:00.000Z",
"status":"Scheduled",
"status_text":"Order processed",
"status_details":"The order has been processed."
}
},
{
"orderNo": "2",
"tracking_number": "002",
"courier": "FedEx",
"street": "637 Britannia Drive",
"zip_code": 94591,
"city": "Vallejo",
"destination_country": "USA",
"email": "test#test.com",
"articleNo": "",
"articleImageUrl": "",
"quantity": "",
"product_name": "",
"items":[
],
"tracking":{
"tracking_number": "002",
"location": "",
"timestamp": "2018-04-06T05:58:00.000Z",
"status": "OrderProcessed",
"status_text": "Order processed",
"status_details": "The order has been processed."
}
}
]
const groupBy = key => array =>
array.reduce(
(objectsByKeyValue, obj) => ({
...objectsByKeyValue,
[obj[key]]: (objectsByKeyValue[obj[key]] || []).concat(obj)
}),
{}
);
const groupByOrders = groupBy('orderNo');
I am looking to get the data in the format shown in data.json
This is the current code along with the data
Code
Below is one possible way to achieve the target.
Code Snippet
const groupAndInclude = (base, delta) => {
const result = []; // result array
base.forEach( // iterate over the "orders"
({ // de-structure to directly access specific props
orderNo, tracking_number, articleNo,
articleImageUrl, quantity, product_name,
...rest // remaining props not directly-accessed
}) => {
const foundOrder = result.find( // find if "order" already in "result"
ob => ob.orderNo === orderNo
);
if (foundOrder) { // found a match, simply push "article"-info
if (articleNo.length > 0) { // push to "items" only if not "empty"
foundOrder.items.push({ // to the "items" array
articleNo, articleImageUrl, quantity, product_name
})
}
} else { // match not-found. Add new entry to "result"
const resObj = { // construct the result-object "resObj"
...rest, orderNo // using all relevant "order" props
};
if (articleNo.length > 0) { // do not add "empty" item
resObj.items = [{ // add "items" as an array
articleNo, articleImageUrl, quantity, product_name
}];
} else {
resObj.items = [];
};
const foundTracker = delta.find( // look for "tracking_number"
ob => ob.tracking_number === tracking_number
);
// if "tracking_number" found, add to result-object
if (foundTracker) resObj.tracking = {...foundTracker};
result.push(resObj); // push the result-object to the "result" array
}
}
);
return result; // explicitly return the "result" array
};
const orders = [{
"orderNo": "1",
"tracking_number": "001",
"courier": "FedEx",
"street": "1745 T Street Southeast",
"zip_code": 20020,
"city": "Louisville",
"destination_country": "USA",
"email": "test#test.com",
"articleNo": "A",
"articleImageUrl": "watch.jpg",
"quantity": 1,
"product_name": "Watch"
},
{
"orderNo": "1",
"tracking_number": "001",
"courier": "FedEx",
"street": "1745 T Street Southeast",
"zip_code": 20020,
"city": "Louisville",
"destination_country": "USA",
"email": "test#test.com",
"articleNo": "B",
"articleImageUrl": "belt.jpg",
"quantity": 2,
"product_name": "Belt"
},
{
"orderNo": "2",
"tracking_number": "002",
"courier": "FedEx",
"street": "637 Britannia Drive",
"zip_code": 94591,
"city": "Vallejo",
"destination_country": "USA",
"email": "test#test.com",
"articleNo": "",
"articleImageUrl": "",
"quantity": "",
"product_name": ""
}
];
//tracking.json
const tracking = [{
"tracking_number": "001",
"location": "",
"timestamp": "2018-04-01T00:00:00.000Z",
"status": "OrderProcessed",
"status_text": "Order processed",
"status_details": "The order has been processed."
},
{
"tracking_number": "002",
"location": "",
"timestamp": "2018-04-06T05:58:00.000Z",
"status": "OrderProcessed",
"status_text": "Order processed",
"status_details": "The order has been processed."
}
];
console.log(groupAndInclude(orders, tracking));
.as-console-wrapper { max-height: 100% !important; top: 0 }
Explanation
Inline comments added in the snippet above.
You could take two objects as reference to same orderNo and tracking_number.
For adding an oder to the result set remove item properties and take a new object of this properties.
const
orders = [{ orderNo: "1", tracking_number: "001", courier: "FedEx", street: "1745 T Street Southeast", zip_code: 20020, city: "Louisville", destination_country: "USA", email: "test#test.com", articleNo: "A", articleImageUrl: "watch.jpg", quantity: 1, product_name: "Watch" }, { orderNo: "1", tracking_number: "001", courier: "FedEx", street: "1745 T Street Southeast", zip_code: 20020, city: "Louisville", destination_country: "USA", email: "test#test.com", articleNo: "B", articleImageUrl: "belt.jpg", quantity: 2, product_name: "Belt" }, { orderNo: "2", tracking_number: "002", courier: "FedEx", street: "637 Britannia Drive", zip_code: 94591, city: "Vallejo", destination_country: "USA", email: "test#test.com", articleNo: "", articleImageUrl: "", quantity: "", product_name: "" }],
tracking = [{ tracking_number: "001", location: "", timestamp: "2018-04-01T00:00:00.000Z", status: "OrderProcessed", status_text: "Order processed", status_details: "The order has been processed." }, { tracking_number: "002", location: "", timestamp: "2018-04-06T05:58:00.000Z", status: "OrderProcessed", status_text: "Order processed", status_details: "The order has been processed." }],
keys = ["articleNo", "articleImageUrl", "quantity", "product_name"],
items = {},
trackings = {},
result = [];
for (let order of orders) {
const item = {};
for (const key of keys) {
let value;
({ [key]: value, ...order } = order);
item[key] = value;
}
if (!items[order.orderNo]) result.push(items[order.orderNo] = { ...order, items: [] });
if (Object.values(item).some(Boolean)) items[order.orderNo].items.push(item);
trackings[order.tracking_number] = items[order.orderNo];
}
for (const transfer of tracking) trackings[transfer.tracking_number].tracking = transfer;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
My mocked data:
[
{
"id": 1,
"first_name": "Suzy",
"last_name": "Pinnell",
"email": "spinnell0#utexas.edu",
"gender": "Agender",
"image": "http://dummyimage.com/410x239.png/5fa2dd/ffffff",
"department": "Marketing",
"job_title": "Quality Control Specialist",
"skill": "Residential Homes"
},
{
"id": 2,
"first_name": "Enriqueta",
"last_name": "Folbig",
"email": "efolbig1#google.com.br",
"gender": "Male",
"image": "http://dummyimage.com/247x244.png/5fa2dd/ffffff",
"department": "Sales",
"job_title": "Environmental Specialist",
"skill": "MMC"
},
{
"id": 3,
"first_name": "Simmonds",
"last_name": "Acomb",
"email": "sacomb2#amazon.co.uk",
"gender": "Polygender",
"image": "http://dummyimage.com/315x256.png/dddddd/000000",
"department": "Human Resources",
"job_title": "Accountant",
"skill": "Xilinx"
},
{
"id": 4,
"first_name": "Bernita",
"last_name": "Hartman",
"email": "bhartman3#whitehouse.gov",
"gender": "Female",
"image": "http://dummyimage.com/305x275.png/dddddd/000000",
"department": "Support",
"job_title": "Account ExecutiveII",
"skill": "Airframe"
}
]
I found a similar question here:
javascript filter array multiple conditions
To define what to filter they pass an object:
var filter = {
gender: 'male',
department: 'Sales'
};
This works. It shows every object containing both keys.
+I tried to modify it, so I could use an array:*
var filter = {
gender: ['Male'],
department: ['Sales', 'Marketing']
};
My goal is to filter the data by the given values in the array. Only items should appear, which contain all males in sales and marketing.
I tried includes (inside filter and a for in loop), but it shows only the results of the first array, the second one is ignored. I am not sure how to achieve a AND condition inside the arrays for all of them.
Thank you.
You could store all entries in advance to prevent to get for each object of data to get the same entries array of the filters.
Filter entries to remove possible empty arrays.
Then take the entries and check if the value is the one of the data or if the filter contains an array, then check if the filter array contains the value from data.
const
data = [{ id: 1, first_name: "Suzy", last_name: "Pinnell", email: "spinnell0#utexas.edu", gender: "Agender", image: "http://dummyimage.com/410x239.png/5fa2dd/ffffff", department: "Marketing", job_title: "Quality Control Specialist", skill: "Residential Homes" }, { id: 2, first_name: "Enriqueta", last_name: "Folbig", email: "efolbig1#google.com.br", gender: "Male", image: "http://dummyimage.com/247x244.png/5fa2dd/ffffff", department: "Sales", job_title: "Environmental Specialist", skill: "MMC" }, { id: 3, first_name: "Simmonds", last_name: "Acomb", email: "sacomb2#amazon.co.uk", gender: "Polygender", image: "http://dummyimage.com/315x256.png/dddddd/000000", department: "Human Resources", job_title: "Accountant", skill: "Xilinx" }, { id: 4, first_name: "Bernita", last_name: "Hartman", email: "bhartman3#whitehouse.gov", gender: "Female", image: "http://dummyimage.com/305x275.png/dddddd/000000", department: "Support", job_title: "Account ExecutiveII", skill: "Airframe" }],
filter = { last_name: [], gender: ['Male'], department: ['Sales', 'Marketing'] },
filterEntries = Object
.entries(filter)
.filter(([, v]) => !Array.isArray(v) || v.length),
result = data.filter(o => filterEntries.every(([k, v]) =>
o[k] === v ||
Array.isArray(v) && v.includes(o[k])
));
console.log(result);
That's a good every use case :)
const data = [
{
"id": 1,
"first_name": "Suzy",
"last_name": "Pinnell",
"email": "spinnell0#utexas.edu",
"gender": "Agender",
"image": "http://dummyimage.com/410x239.png/5fa2dd/ffffff",
"department": "Marketing",
"job_title": "Quality Control Specialist",
"skill": "Residential Homes"
},
{
"id": 2,
"first_name": "Enriqueta",
"last_name": "Folbig",
"email": "efolbig1#google.com.br",
"gender": "Male",
"image": "http://dummyimage.com/247x244.png/5fa2dd/ffffff",
"department": "Sales",
"job_title": "Environmental Specialist",
"skill": "MMC"
},
{
"id": 3,
"first_name": "Simmonds",
"last_name": "Acomb",
"email": "sacomb2#amazon.co.uk",
"gender": "Polygender",
"image": "http://dummyimage.com/315x256.png/dddddd/000000",
"department": "Human Resources",
"job_title": "Accountant",
"skill": "Xilinx"
},
{
"id": 4,
"first_name": "Bernita",
"last_name": "Hartman",
"email": "bhartman3#whitehouse.gov",
"gender": "Female",
"image": "http://dummyimage.com/305x275.png/dddddd/000000",
"department": "Support",
"job_title": "Account ExecutiveII",
"skill": "Airframe"
}
]
const filter = {
gender: ['Male'],
department: ['Sales', 'Marketing']
}
const result = data.filter(item => (
Object.entries(filter).every(([key, arr]) => arr.includes(item[key]))
))
console.log(result)
Instead of negating the === operator, you can negate an includes call:
data = data.filter(function(item) {
for (var key in filter) {
if (item[key] === undefined || !filter[key].includes(item[key]))
return false;
}
return true;
});
You can acheive your expected result by iterating over your filter object and on the every iteration, checking target object can pass your filter or not (in below snippet I've used Object.entries and every method to do that), like this:
const data = [
{
"id": 1,
"first_name": "Suzy",
"last_name": "Pinnell",
"email": "spinnell0#utexas.edu",
"gender": "Agender",
"image": "http://dummyimage.com/410x239.png/5fa2dd/ffffff",
"department": "Marketing",
"job_title": "Quality Control Specialist",
"skill": "Residential Homes"
},
{
"id": 2,
"first_name": "Enriqueta",
"last_name": "Folbig",
"email": "efolbig1#google.com.br",
"gender": "Male",
"image": "http://dummyimage.com/247x244.png/5fa2dd/ffffff",
"department": "Sales",
"job_title": "Environmental Specialist",
"skill": "MMC"
},
{
"id": 3,
"first_name": "Simmonds",
"last_name": "Acomb",
"email": "sacomb2#amazon.co.uk",
"gender": "Polygender",
"image": "http://dummyimage.com/315x256.png/dddddd/000000",
"department": "Human Resources",
"job_title": "Accountant",
"skill": "Xilinx"
},
{
"id": 4,
"first_name": "Bernita",
"last_name": "Hartman",
"email": "bhartman3#whitehouse.gov",
"gender": "Female",
"image": "http://dummyimage.com/305x275.png/dddddd/000000",
"department": "Support",
"job_title": "Account ExecutiveII",
"skill": "Airframe"
}
];
const filter = {
gender: ['Male'],
department: ['Sales', 'Marketing']
}
const createFilterFun = filters => obj => Object.entries(filters).every( ([k, v]) => v.includes(obj[k]) );
const filterByGenderAndDepratment = createFilterFun(filter);
const result = data.filter(filterByGenderAndDepratment);
console.log(result)
try this
var itemsFilter = {
gender: ['Male'],
department: ['Sales', 'Marketing']
};
users= users.filter (function(item) {
var find=false;
for (var key in itemsFilter) {
find=false;
if (item[key] === undefined) return false;
for (var k in itemsFilter[key])
if (itemsFilter[key][k] == item[key]) find=true;
if (find==false) return false;
};
return find;
});
I have an Array of Key names (let's call it 'Labels') and another array of Objects (let's call it 'Data'). I am trying to convert Data Array into Parent Child structure by using the hierarchy of Labels Array. That means, First Data will be grouped by "Gender" (parent) and then "Age" (children of Gender) and then "ID" (children of Age)
//.... means it can be any number of items
var Labels = ["Gender", "Age", "ID", ....];
var Data = [{
"Age":"22",
"Gender":"Male",
"ID":"A111"
},
{
"Age":"22",
"Gender":"Male",
"ID":"A113"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A109"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A115"
},
{
"Age":"22",
"Gender":"Male",
"ID":"A105"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A107"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A103"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A101"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A114"
},
{
"Age":"23",
"Gender":"Female",
"ID":"A112"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A108"
},
{
"Age":"21",
"Gender":"Female",
"ID":"A104"
},
{
"Age":"23",
"Gender":"Female",
"ID":"A106"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A102"
},
{
"Age":"21",
"Gender":"Female",
"ID":"A110"
},
{
"Age":"22",
"Gender":"Male",
"ID":"A111"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A113"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A109"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A115"
},
{
"Age":"22",
"Gender":"Male",
"ID":"A105"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A107"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A103"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A101"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A114"
},
{
"Age":"23",
"Gender":"Female",
"ID":"A112"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A108"
},
{
"Age":"21",
"Gender":"Female",
"ID":"A104"
},
{
"Age":"23",
"Gender":"Female",
"ID":"A106"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A102"
},
{
"Age":"21",
"Gender":"Female",
"ID":"A110"
},
{
"Age":"22",
"Gender":"Male",
"ID":"A111"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A113"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A109"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A115"
},
{
"Age":"22",
"Gender":"Male",
"ID":"A105"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A107"
},
{
"Age":"23",
"Gender":"Male",
"ID":"A103"
},
{
"Age":"21",
"Gender":"Male",
"ID":"A101"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A114"
},
{
"Age":"23",
"Gender":"Female",
"ID":"A112"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A108"
},
{
"Age":"21",
"Gender":"Female",
"ID":"A104"
},
{
"Age":"23",
"Gender":"Female",
"ID":"A106"
},
{
"Age":"22",
"Gender":"Female",
"ID":"A102"
},
{
"Age":"21",
"Gender":"Female",
"ID":"A110"
}]
Expected Output of above Data should be:
var output = [{
name: "Male",
childrens:[
{
name: "21",
childrens: [{name: "Al01"},{name: "Al07"}, ....]
},
{
name: "22",
childrens: [{name: "A111"},{name: "A113"}, ....]
},
{
name: "23",
childrens: [{name: "A109"},{name: "A115"}, ....]
}
]
},
{
name: "Female",
childrens:[
{
name: "21",
childrens: [{name: "Al04"},{name: "Al10"}, ....]
},
{
name: "22",
childrens: [{name: "A102"},{name: "A114"}, ....]
},
{
name: "23",
childrens: [{name: "A106"},{name: "A109"}, ....]
}
]
}];
I've tried groupBy() as shown below But not getting the expected output.
var groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
function calcCats(ca, ss) {
let K2 = groupBy(ca, ss);
ca = [];
Object.keys(K2).forEach(cc => {
K2[cc].forEach(kk=>{
delete kk[ss];
});
let tv = { name: cc, type: ss };
if(Object.keys(K2[cc][0]).length > 0)
{
tv.categories= K2[cc];
}
ca.push(tv);
});
return ca;
}
var output = [];
Labels.forEach((ss, i) => {
if (output.length <= 0) {
let K1 = groupBy(output, ss);
Object.keys(K1).forEach(cc => {
output.push({ name: cc, categories: K1[cc] });
});
} else {
output.forEach(ca => {
ca.categories = calcCats(ca.categories, ss);
});
}
});
You could take an object which keeps the references to the groups for the actual level, and the array of the results of the level in a nested style and aff a new level from an array of keys.
Let us have a look to the object (_ and the rest properties are switched)
{
"Male": {
"21": {
"_": /**ref:1a**/
},
"22": {
"_": /**ref:6**/
},
"23": {
"_": /**ref:f**/
},
"_": /**ref:4**/
},
"Female": {
"21": {
"_": /**ref:39**/
},
"22": {
"_": /**ref:26**/
},
"23": {
"_": /**ref:31**/
},
"_": /**ref:24**/
},
"_": [
{
"name": "Male",
"children": [
/**id:4**/
{
"name": "22",
"children": [
/**id:6**/
{ "ID": "A111" },
{ "ID": "A113" },
// ...
]
},
{
"name": "23",
"children": [
/**id:f**/
{ "ID": "A109" },
{ "ID": "A115" },
// ...
]
},
{
"name": "21",
"children": [
/**id:1a**/
{ "ID": "A107" },
{ "ID": "A101" },
// ...
]
}
]
},
{
"name": "Female",
"children": [
/**id:24**/
{
"name": "22",
"children": [
/**id:26**/
{ "ID": "A114" },
{ "ID": "A108" },
// ...
]
},
{
"name": "23",
"children": [
/**id:31**/
{ "ID": "A112" },
{ "ID": "A106" },
// ...
]
},
{
"name": "21",
"children": [
/**id:39**/
{ "ID": "A104" },
{ "ID": "A110" },
// ...
]
}
]
}
]
}
The object contains nested groups of first level Gender with Male/Female and another level Age with their values and a reference to an array.
This is not the wanted structure for the result.
The result contains arrays of objects with a name property which reflects the level value and later an object without the grouping properties.
In depth:
The outer reduce iterates the given objects. As well as it keeps the object for each iteration and this allowes to use the object with a fast access to the nested groups.
The inner reduce takes a level and a key for this level and destructure the key from the object to get an object without the key for the actual level.
If the level does not have a property with the actual group value, then a new property with the name and an object with only one property _ is created with an array as value. the array contains all values of the level. The underscore is needed to prevent a conflict with other values of the grouping value.
Actually only the first structure is creater, this would not appear in the result set, right now. For having this array in the result set, it need to add an object with a reference to the array as children.
Finall the object with the level group is returned.
At the leaves the rest of the data object has to pushed to the array.
const
data = [{ Age: "22", Gender: "Male", ID: "A111" }, { Age: "22", Gender: "Male", ID: "A113" }, { Age: "23", Gender: "Male", ID: "A109" }, { Age: "23", Gender: "Male", ID: "A115" }, { Age: "22", Gender: "Male", ID: "A105" }, { Age: "21", Gender: "Male", ID: "A107" }, { Age: "23", Gender: "Male", ID: "A103" }, { Age: "21", Gender: "Male", ID: "A101" }, { Age: "22", Gender: "Female", ID: "A114" }, { Age: "23", Gender: "Female", ID: "A112" }, { Age: "22", Gender: "Female", ID: "A108" }, { Age: "21", Gender: "Female", ID: "A104" }, { Age: "23", Gender: "Female", ID: "A106" }, { Age: "22", Gender: "Female", ID: "A102" }, { Age: "21", Gender: "Female", ID: "A110" }, { Age: "22", Gender: "Male", ID: "A111" }, { Age: "21", Gender: "Male", ID: "A113" }, { Age: "23", Gender: "Male", ID: "A109" }, { Age: "23", Gender: "Male", ID: "A115" }, { Age: "22", Gender: "Male", ID: "A105" }, { Age: "21", Gender: "Male", ID: "A107" }, { Age: "23", Gender: "Male", ID: "A103" }, { Age: "21", Gender: "Male", ID: "A101" }, { Age: "22", Gender: "Female", ID: "A114" }, { Age: "23", Gender: "Female", ID: "A112" }, { Age: "22", Gender: "Female", ID: "A108" }, { Age: "21", Gender: "Female", ID: "A104" }, { Age: "23", Gender: "Female", ID: "A106" }, { Age: "22", Gender: "Female", ID: "A102" }, { Age: "21", Gender: "Female", ID: "A110" }, { Age: "22", Gender: "Male", ID: "A111" }, { Age: "21", Gender: "Male", ID: "A113" }, { Age: "23", Gender: "Male", ID: "A109" }, { Age: "23", Gender: "Male", ID: "A115" }, { Age: "22", Gender: "Male", ID: "A105" }, { Age: "21", Gender: "Male", ID: "A107" }, { Age: "23", Gender: "Male", ID: "A103" }, { Age: "21", Gender: "Male", ID: "A101" }, { Age: "22", Gender: "Female", ID: "A114" }, { Age: "23", Gender: "Female", ID: "A112" }, { Age: "22", Gender: "Female", ID: "A108" }, { Age: "21", Gender: "Female", ID: "A104" }, { Age: "23", Gender: "Female", ID: "A106" }, { Age: "22", Gender: "Female", ID: "A102" }, { Age: "21", Gender: "Female", ID: "A110" }],
keys = ['Gender', 'Age'],
tree = data
.reduce((r, o) => {
keys
.reduce((level, key) => {
let name;
({ [key]: name, ...o } = o);
if (!level[name]) {
level[name] = { _: [] };
level._.push({ name, children: level[name]._ });
}
return level[name];
}, r)
._
.push(o);
return r;
}, { _: [] })
._;
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
What i am trying to do is filter one object using another. I have it working for the keys such as name or email but the problem is for the address field where it needs to check the value recursively.
I have the following object:
{
"id" : 1,
"name": "Michael",
"surname": "Smith",
"emailAddress": "m.smith#gmail.com",
},
{
"id": "2",
"name": "Sam",
"surname": "Smith",
"emailAddress": "s.smith#gmail.com",
"address": {
"text": "123 Fake Street, Some Place, United kingdom",
"street_number": "123",
"route": "Fake Street",
"locality": "Some Place",
"country": "UK",
"postcode": "HP18",
"lat": 51.648858999292999,
"lng": 4.08207329992999786,
}
},
{
"id": 3,
"name": "Josh",
"surname": "Fradley",
"emailAddress": "myemai#gmail.com",
"address": {
"text": "1 Apple Park Way, Cupertino, CA, USA",
"street_number": "1",
"route": "Apple Park Way",
"locality": "Cupertino",
"administrative_area_level_1": "California",
"country": "US",
"postcode": "95014",
"lat": 37.3346326,
"lng": -122.01268240000002,
}
}
]
Example search object
{
"name": "",
"phone": "",
"address": "",
"emailAddress": "myemai#gmail.com"
}
The code i use for the email and name fields
let res = array.filter(o =>
Object.keys(searches).every(k =>
o[k] && o[k].length ? removeDiacritics(o[k].toLowerCase()).indexOf(removeDiacritics(searches[k].toLowerCase())) >= 0 : true
));
What i am struggling with is how to search the address key which is an object, for example if i search "address": "Fake Street" it should return id 2
Any suggestions?
EDIT: I forgot to mention that the filters array is dynamic so i cant hard code in "address", i used here as an example of an object
You could take a local function and check the value of the object for nested objects.
var data = [{ id: 1, name: "Michael", surname: "Smith", emailAddress: "m.smith#gmail.com" }, { id: "2", name: "Sam", surname: "Smith", emailAddress: "s.smith#gmail.com", address: { text: "123 Fake Street, Some Place, United kingdom", street_number: "123", route: "Fake Street", locality: "Some Place", country: "UK", postcode: "HP18", lat: 51.648858999293, lng: 4.082073299929998 } }, { id: 3, name: "Josh", surname: "Fradley", emailAddress: "myemai#gmail.com", address: { text: "1 Apple Park Way, Cupertino, CA, USA", street_number: "1", route: "Apple Park Way", locality: "Cupertino", administrative_area_level_1: "California", country: "US", postcode: "95014", lat: 37.3346326, lng: -122.01268240000001 } }],
search = { name: "", phone: "", address: 123, emailAddress: "" },
result = data.filter(o => Object.entries(search).every(([k, v]) => {
function check(value) {
return value && typeof value === 'object'
? Object.values(value).some(check)
: value.toString().includes(v);
}
if (v === '') return true;
if (k in o) return check(o[k]);
}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
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; }