Keys problems when mapping using Lodash - javascript

I am trying to get my monthly sales and put them on the chart. They're going to be grouped by year. This is what I've done so far:
let result = _
.chain(res.data)
.groupBy("_id.year")
.value();
result = _.map(result, (yearlyValues, key) => {
return {
[key]: _.map(yearlyValues, yearlyValuesItems => {
return {
[yearlyValuesItems._id.month]: yearlyValuesItems.count
};
})
};
});
result = _.map(result, (value, key) => {
return _.map(value, (innerValues, innerKey) => {
return innerValues;
})
})
result = _.flatten(result);
result = _.map(result, (value, key) => {
return _.map(value, (items, keys) => {
return _.map(items, (a, b) => {
return a
})
})
});
for (var i in result) {
final_count.push(_.flatten(result[i]));
}
console.log(final_count);
$scope.labels_monthly = monthNames;
$scope.series = Object.keys(final_count);
$scope.data = Object.values(final_count);
$scope.options = {
legend: {
display: true
}
};
My data: https://pastebin.com/WhJ0atTX
My output: https://jsfiddle.net/asfxtor4/1/
My problem is that I am getting keys 0, 1, 2 instead of 2016, 2017, 2018.
And then inside I need to get key as a month number.This key has to be 2 because the month is March, but it generates 0. You can see in the pictures.
This is my desired output: https://pastebin.com/iChhrnNG, I need to get an array of all months and if there is data for just March lets say, all other array elements should be 0.

You can get an array of objects with years and values by adding 'entries' e.g.
let result = _
.chain(data)
.groupBy("_id.year")
.entries()
.value()
.map((item) => ({year: item[0], values: item[1]}));
You then won't need:
result = _.map(result, (yearlyValues, key) => {
return {
[key]: _.map(yearlyValues, yearlyValuesItems => {
return {
[yearlyValuesItems._id.month]: yearlyValuesItems.count
};
})
};
});
You can see a fiddle here:
https://jsfiddle.net/Fresh/yr8bqteL/
Hopefully this info will help you complete this assignment.

Since you know you always have 12 months you could be somewhat less fancy and do this:
data = [{
"_id": {
"month": 12,
"year": 2018
},
"count": 3
},
{
"_id": {
"month": 11,
"year": 2018
},
"count": 4
},
{
"_id": {
"month": 9,
"year": 2018
},
"count": 3
},
{
"_id": {
"month": 8,
"year": 2018
},
"count": 4
},
{
"_id": {
"month": 5,
"year": 2018
},
"count": 4
},
{
"_id": {
"month": 7,
"year": 2018
},
"count": 2
},
{
"_id": {
"month": 4,
"year": 2018
},
"count": 5
},
{
"_id": {
"month": 9,
"year": 2017
},
"count": 2
},
{
"_id": {
"month": 8,
"year": 2017
},
"count": 4
},
{
"_id": {
"month": 11,
"year": 2017
},
"count": 4
},
{
"_id": {
"month": 10,
"year": 2017
},
"count": 3
},
{
"_id": {
"month": 4,
"year": 2017
},
"count": 2
},
{
"_id": {
"month": 2,
"year": 2017
},
"count": 3
},
{
"_id": {
"month": 6,
"year": 2017
},
"count": 1
},
{
"_id": {
"month": 1,
"year": 2018
},
"count": 4
},
{
"_id": {
"month": 2,
"year": 2018
},
"count": 4
},
{
"_id": {
"month": 3,
"year": 2018
},
"count": 9
},
{
"_id": {
"month": 10,
"year": 2018
},
"count": 3
},
{
"_id": {
"month": 3,
"year": 2017
},
"count": 9
},
{
"_id": {
"month": 7,
"year": 2017
},
"count": 2
},
{
"_id": {
"month": 12,
"year": 2017
},
"count": 3
},
{
"_id": {
"month": 3,
"year": 2016
},
"count": 1
},
{
"_id": {
"month": 1,
"year": 2017
},
"count": 3
},
{
"_id": {
"month": 6,
"year": 2018
},
"count": 3
}
]
let result = _
.chain(data)
.groupBy("_id.year")
.reduce((obj, current, index) => {
var sortedMonths = _.sortBy(current, (v) => v._id.month), monthsArray = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
_.map(current, (curObj, i) => monthsArray[_.get(sortedMonths, '[' + i + ']._id.month') - 1] = sortedMonths[i].count)
return _.extend(obj, { [index]: monthsArray })
}, {})
.value();
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Related

Merge array of an object based on a common field

I have an object that looks like as follows:
[
{
"Net_Amount": 499,
"Date": "2022-01-09T18:30:00.000Z",
"Scheme_Name": "CUSTOMERWINBACKJCA01",
"Month": "Jan"
},
{
"Net_Amount": 902,
"Date": "2022-01-09T18:30:00.000Z",
"Scheme_Name": "CUSTOMERWINBACKJCA02",
"Month": "Jan"
},
{
"Net_Amount": 1860,
"Date": "2022-10-01T18:30:00.000Z",
"Scheme_Name": "CUSTOMERCONNECTJCA",
"Month": "Oct"
},
{
"Net_Amount": 1889,
"Date": "2022-11-01T18:30:00.000Z",
"Scheme_Name": "CUSTOMERCONNECTJCA",
"Month": "Nov"
}
]
Now, if you will look carefully, I have a common field Month in the objects and I want merge the objects based on this common field only. How I want my object to be formatted is as :
[
{
"Month": "Jan",
"varData": [{
"Net_Amount": 499,
"Date": "2022-01-09T18:30:00.000Z",
"Scheme_Name": "CUSTOMERWINBACKJCA01"
},
{
"Net_Amount": 902,
"Date": "2022-01-09T18:30:00.000Z",
"Scheme_Name": "CUSTOMERWINBACKJCA02"
}]
},
{
"Month": "Oct",
"varData": [{
"Net_Amount": 1860,
"Date": "2022-10-01T18:30:00.000Z",
"Scheme_Name": "CUSTOMERCONNECTJCA"
}]
},
{
"Month": "Nov",
"varData": [{
"Net_Amount": 1889,
"Date": "2022-11-01T18:30:00.000Z",
"Scheme_Name": "CUSTOMERCONNECTJCA"
}]
}
]
I can do it by iterating over the array and checking if month is same, then pushing the other key and its value of object in the varData but I want to know if there is any shortcut or inbuilt function which I can use to achieve my purpose.
I don't think that there is some better built-in solution then iterating the array.
But if you use month names as keys then the code could be quite straightforward (the output is not exactly the same but quite similarly structured).
const result = {}
for (const entry of list) {
if (!result[entry.Month]) {
result[entry.Month] = []
}
result[entry.Month].push(entry)
}
See jsfiddle.
If you need the output that is exactly specified in the question then you can use the following code:
let result = {}
for (const entry of list) {
const month = entry.Month
if (!result[month]) {
result[month] = {
"Month": month,
"varData": []
}
}
delete entry.Month
result[month].varData.push(entry)
}
result = Object.values(result)
See jsfiddle
const data = [{"Net_Amount":499,"Date":"2022-01-09T18:30:00.000Z","Scheme_Name":"CUSTOMERWINBACKJCA01","Month":"Jan"},{"Net_Amount":902,"Date":"2022-01-09T18:30:00.000Z","Scheme_Name":"CUSTOMERWINBACKJCA02","Month":"Jan"},{"Net_Amount":1860,"Date":"2022-10-01T18:30:00.000Z","Scheme_Name":"CUSTOMERCONNECTJCA","Month":"Oct"},{"Net_Amount":1889,"Date":"2022-11-01T18:30:00.000Z","Scheme_Name":"CUSTOMERCONNECTJCA","Month":"Nov"}]
console.log([...new Set(data.map(i=>i.Month))].map(Month=>
({Month, varData: data.filter(({Month:m})=>m===Month).map(({Month,...o})=>o)})))
const dataArr = [
{
Net_Amount: 499,
Date: "2022-01-09T18:30:00.000Z",
Scheme_Name: "CUSTOMERWINBACKJCA01",
Month: "Jan",
},
{
Net_Amount: 902,
Date: "2022-01-09T18:30:00.000Z",
Scheme_Name: "CUSTOMERWINBACKJCA02",
Month: "Jan",
},
{
Net_Amount: 1860,
Date: "2022-10-01T18:30:00.000Z",
Scheme_Name: "CUSTOMERCONNECTJCA",
Month: "Oct",
},
{
Net_Amount: 1889,
Date: "2022-11-01T18:30:00.000Z",
Scheme_Name: "CUSTOMERCONNECTJCA",
Month: "Nov",
},
];
const outputObj = dataArr.reduce((acc, crt) => {
acc[crt.Month] ??= [];
acc[crt.Month].push(crt);
return acc;
}, {});
const outputArr = Object.values(outputObj).map((item) => ({ Month: item[0].Month, varData: item }));
console.log(outputArr);

JS\Node Reduce group by multiple properties and summarize JSON data

I have following data that i'm trying to group summarize and add back to related object.
{
"Schedule": [
{
"AppointmentId": 123456,
"Start": "2021-11-02T09:00:00.000Z",
"Location": 87925,
"InsuranceName": "Geico",
"InsuranceFinancialClass": "Commercial",
"AppointmentName": "Online",
"LocalDate": "11/02/2021",
"LocalTime": "9:00 AM",
"TimeOfDay": "AM"
},
{
"AppointmentId": 123457,
"Start": "2021-11-03T10:00:00.000Z",
"Location": 87925,
"InsuranceName": "Farmers",
"InsuranceFinancialClass": "Commercial",
"AppointmentName": "InPerson",
"LocalDate": "11/03/2021",
"LocalTime": "10:00 AM",
"TimeOfDay": "AM"
},
{
"AppointmentId": 123458,
"Start": "2021-11-03T11:00:00.000Z",
"Location": 87925,
"InsuranceName": "Farmers",
"InsuranceFinancialClass": "Commercial",
"AppointmentName": "InPerson",
"LocalDate": "11/03/2021",
"LocalTime": "11:00 AM",
"TimeOfDay": "AM"
}
]
}
I would like the final result to look like the following:
{
"Schedule": [
{
"AppointmentId": 123456,
"Start": "2021-11-02T09:00:00.000Z",
"Location": 87925,
"InsuranceName": "Geico",
"InsuranceFinancialClass": "Commercial",
"AppointmentName": "Online",
"LocalDate": "11/02/2021",
"LocalTime": "9:00 AM",
"TimeOfDay": "AM",
"Summary": {
"InsuranceName": {
"Total": 1,
"Geico": 1
},
"InsuranceFinancialClass": {
"Total": 1,
"Commercial": 1
},
"AppointmentName": {
"Total": 1,
"Online": 1,
"InPerson": 1
},
"LocalDate": {
"Total": 1,
"11/02/2021": 1,
}
}
},
{
"AppointmentId": 123457,
"Start": "2021-11-03T10:00:00.000Z",
"Location": 87925,
"InsuranceName": "Farmers",
"InsuranceFinancialClass": "Commercial",
"AppointmentName": "InPerson",
"LocalDate": "11/03/2021",
"LocalTime": "10:00 AM",
"TimeOfDay": "AM",
"Summary": {
"InsuranceName": {
"Total": 2,
"Farmers": 2
},
"InsuranceFinancialClass": {
"Total": 2,
"Commercial": 2
},
"AppointmentName": {
"Total": 2,
"InPerson": 2
},
"LocalDate": {
"Total": 2,
"11/03/2021": 2
}
}
}
{
"AppointmentId": 123458,
"Start": "2021-11-03T11:00:00.000Z",
"Location": 87925,
"InsuranceName": "Farmers",
"InsuranceFinancialClass": "Commercial",
"AppointmentName": "InPerson",
"LocalDate": "11/03/2021",
"LocalTime": "11:00 AM",
"TimeOfDay": "AM",
"Summary": {
"InsuranceName": {
"Total": 2,
"Farmers": 2
},
"InsuranceFinancialClass": {
"Total": 2,
"Commercial": 2
},
"AppointmentName": {
"Total": 2,
"InPerson": 2
},
"LocalDate": {
"Total": 2,
"11/03/2021": 2
}
}
}
]
}
I have following JS code that:
const props = ['LocalDate', 'AppointmentName', 'InsuranceFinancialClass', 'InsuranceName'];
const result = JSONData.reduce((r, e) => {
Object.entries(e).forEach(([k, v]) => {
if (props.includes(k)) {
if (!r[k]) r[k] = {};
r[k].Total = (r[k].Total || 0) + 1;
r[k][v] = (r[k][v] || 0) + 1;
}
});
return r;
}, {});
{
"Schedule": {
"InsuranceName": {
"Total": 3,
"Geico": 1,
"Farmers": 2
},
"InsuranceFinancialClass": {
"Total": 3,
"Commercial": 3
},
"AppointmentName": {
"Total": 3,
"Online": 1,
"InPerson": 2
},
"LocalDate": {
"Total": 3,
"11/02/2021": 1,
"11/03/2021": 2
}
}
}
How should the code be written produce desired result?
The summary object should be aggregate by date and appended to original object that matches the date.
Thanks in advance for your help and suggestions.
I was able to work out a solution but not sure if it's efficient.
const props = ['LocalDate', 'AppointmentName', 'InsuranceFinancialClass', 'InsuranceName'];
const groupedByDateSummary = filteredByPatientAppointment.reduce((r, e) => {
if (!r[e.LocalDate]) r[e.LocalDate] = {};
Object.entries(e).forEach(([k, v]) => {
if (props.includes(k)) {
if (!r[e.LocalDate][k]) r[e.LocalDate][k] = {};
r[e.LocalDate][k].Total = (r[e.LocalDate][k].Total || 0) + 1;
r[e.LocalDate][k][v] = (r[e.LocalDate][k][v] || 0) + 1;
}
});
return r;
}, {});
const slotObjWithSummary = _.each(filteredByPatientAppointment, (summary) => {
for (const [key, value] of Object.entries(groupedByDateSummary)) {
if (key === summary.LocalDate) {
summary.Summary = value;
}
}
return summary;
});

Getting dates from JSON for D3

My JSON file has the dates separated like this:
"time": {
"date": {
"year": 2018,
"month": 2,
"day": 25
},
"time": {
"hour": 10,
"minute": 19,
"second": 6,
"nano": 19000000
}
},
The tutorial I used to get a line graph in d3 going was in this link:
https://datawanderings.com/2019/10/28/tutorial-making-a-line-chart-in-d3-js-v-5/
Using the code below:-
const timeConv = d3.timeParse("%d-%b-%Y");
const dataset = d3.csv(datacsv);
dataset.then(function(data) {
var slices = data.columns.slice(1).map(function(id) {
return {
id: id,
values: data.map(function(d){
return {
date: timeConv(d.date),
measurement: +d[id]
};
})
};
});
});
How could I use the same code but use the JSON file with the separated date values?
Just make up the actual date string from the separate dates:
return {
date: timeConv(d.time.date.day + '-' + d.time.date.month + '-' + d.time.date.year),
measurement: +d[id]
};
Since the month is not described as the abbreviated month name, you need to change timeConv as
const timeConv = d3.timeParse("%d-%m-%Y");
An json data example:
let dataset = [{
"id": 1,
"time": {
"date": {
"year": 2018,
"month": 2,
"day": 25
},
"time": {
"hour": 10,
"minute": 19,
"second": 6,
"nano": 19000000
}
}
}, {
"id": 2,
"time": {
"date": {
"year": 2019,
"month": 2,
"day": 25
},
"time": {
"hour": 10,
"minute": 19,
"second": 6,
"nano": 19000000
}
}
}]
const timeConv = d3.timeParse("%d-%m-%Y");
newData = dataset.map(function(d) {
return {
date: timeConv(d.time.date.day + '-' + d.time.date.month + '-' + d.time.date.year),
measurement: +d.id
}
})
console.log(newData)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Javascript: rearrage json output in a specific array format

Another dumb moment for me. Spent hours through for loops, maps, reduce, dictionaries but just can't seem to figure it out. I have a json data that look like this
{
"timeline": [
{
"series": "series1",
"data": [
{
"date": "20200713T120000Z",
"value": 0
},
{
"date": "20200714T120000Z",
"value": 8
},
{
"date": "20200715T120000Z",
"value": 0
}
]
},
{
"series": "series2",
"data": [
{
"date": "20200713T120000Z",
"value": 0
},
{
"date": "20200714T120000Z",
"value": 0
}
]
},
{
"series": "series3",
"data": [
{
"date": "20200713T120000Z",
"value": 1
},
{
"date": "20200714T120000Z",
"value": 0
}
]
},
{
"series": "series4",
"data": [
{
"date": "20200713T120000Z",
"value": 2
},
{
"date": "20200714T120000Z",
"value": 4
}
]
}
]
}
I need it in this format
[
{
date: "20200713T120000Z",
series1: 0,
series2: 0,
series3: 1,
series4: 2
},
{
date: "20200714T120000Z",
series1: 8,
series2: 0,
series3: 0,
series4: 4
}
]
Need to do this in JavaScript. Any help/ pointers will be much appreciated.
You could take an object forgrouping and an array for storing all keys for getting an ordered result with all same keys.
This approach filters all zero values from the result set.
const
data = { timeline: [{ series: "series1", data: [{ date: "20200713T120000Z", value: 0 }, { date: "20200714T120000Z", value: 8 }, { date: "20200715T120000Z", value: 0 }] }, { series: "series2", data: [{ date: "20200713T120000Z", value: 0 }, { date: "20200714T120000Z", value: 0 }] }, { series: "series3", data: [{ date: "20200713T120000Z", value: 1 }, { date: "20200714T120000Z", value: 0 }] }, { series: "series4", data: [{ date: "20200713T120000Z", value: 2 }, { date: "20200714T120000Z", value: 4 }] }] },
keys = ['date'],
result = Object
.values(data.timeline.reduce((r, { series, data }) => {
keys.push(series);
data.forEach(({ date, value }) => {
if (!value) return;
if (!r[date]) r[date] = { date };
r[date][series] = value;
});
return r;
}, {}))
.map(o => ({ ...Object.fromEntries(keys.map(k => [k, 0])), ...o }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is temporary solution for this, you can try this. I'm using lodash, so please install it.
var _ = require('lodash')
const data = {"timeline": [ { "series": "series1", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 8 },{ "date": "20200715T120000Z", "value": 0 }] },{ "series": "series2", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series3", "data": [ { "date": "20200713T120000Z", "value": 1 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series4", "data": [ { "date": "20200713T120000Z", "value": 2 },{ "date": "20200714T120000Z", "value": 4 }] }] }
const t = _.flattenDeep(data.timeline.map(i => i.data.map(d => ({...d, series: i.series}))))
const result = t.reduce((acc, i) => {
const index = acc.findIndex(a => a.date === i.date)
if(index !== -1){
acc[index] = {
...acc[index],
[i.series]: i.value
}
}else {
acc.push({
date: i.date,
[i.series]: i.value
})
}
return acc
}, [])
console.log(result)
Use multiple forEach loops and build an object to track. Then get Object.values
const convert = (arr) => {
const res = {};
arr.forEach(({ series, data }) =>
data.forEach(
({ date, value }) =>
(res[date] = { ...(res[date] ?? { date }), [series]: value })
)
);
return Object.values(res);
};
obj = {"timeline": [ { "series": "series1", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 8 },{ "date": "20200715T120000Z", "value": 0 }] },{ "series": "series2", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series3", "data": [ { "date": "20200713T120000Z", "value": 1 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series4", "data": [ { "date": "20200713T120000Z", "value": 2 },{ "date": "20200714T120000Z", "value": 4 }] }] }
const res = convert(obj.timeline);
console.log(res)

How can I sort the summed up number from JSON

I have the JSON look like below. I'm finding the way to sort the numberOfPoint after I summed up.
{ "data": [
{
"id": {
"year": 2015,
"Name": "A"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2014,
"Name": "C"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2014,
"Name": "B"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2014,
"Name": "B"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2013,
"Name": "C"
},
"numberOfPoint": 2
}]
}
obj is my JSON.
var result = {};
obj.data.forEach(function (a) { result[a["id"]["Name"]] = (result[a["id"]["Name"]] || 0) + a["numberOfPoint"]; });
result is look like below
{
"A": 2,
"C": 4,
"B": 4
}
How can I sort this from largest to lowest numberOfPoint?
I want the result like this.
{
"B": 4,
"C": 4,
"A": 2
}
Thank you in advance.
You can do as below :
var result={
"A": 2,
"C": 4,
"B": 4,
"D": 3
}
var temp = [];
$.each(result, function(key, value) {
temp.push({v:value, k: key});
});
temp.sort(function(a,b){
if(a.v < b.v){ return 1}
if(a.v > b.v){ return -1}
return 0;
});
$.each(temp, function(index, obj) {
alert(obj.k + "-" + obj.v);
});
Here is JSFiddle
Maybe this will help.
obj.data.sort(function(a, b) {
return a.id.Name < b.id.Name;
});
for(var i in obj.data) {
console.log(obj.data[i].id.Name);
}
var obj = { "data": [
{
"id": {
"year": 2015,
"Name": "A"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2014,
"Name": "C"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2014,
"Name": "B"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2014,
"Name": "B"
},
"numberOfPoint": 2
},
{
"id": {
"year": 2013,
"Name": "C"
},
"numberOfPoint": 2
}] }
var result = {};
obj.data.forEach(function (a) {
result[a["id"]["Name"]] = (result[a["id"]["Name"]] || 0) + a["numberOfPoint"];
});
var temp = [];
$.each(result, function(key, value) {
temp.push({v:value, k: key});
}); temp.sort(function(a,b){ if(a.v < b.v){ return 1}
if(a.v > b.v){ return -1}
return 0; });
$.each(temp, function(index, obj) {
alert(obj.k + "-" + obj.v); });
I hope you like this..if you like then don't forget to vote me..and thanks #Butani Vijay for nice sorting. i have implemented in common...

Categories

Resources