How to prevent object properties from being overwritten - javascript

I'm building a function that creates a nested object with dynamic properties which has the year and month as keys.
const sixMonthSummary = {};
// This will get data for the latest 6 months
for (let i = 0; i <= 6; i++) {
const currentDate = new Date();
const [, month, year] = new Date(
currentDate.setMonth(currentDate.getMonth() - i)
)
.toLocaleDateString("en-SG")
.split("/");
sixMonthSummary[year] = {
[month]: {
rent: "",
income: "",
expenses: "",
},
};
}
console.log(sixMonthSummary)
The output only captures the last index and the first index instead
"2020": {
"07": {
"rent": "",
"income": "",
"expenses": ""
}
},
"2021": {
"01": {
"rent": "",
"income": "",
"expenses": ""
}
}
How do I make sure that the other months are not missed out?

You are overwriting the complete object-key at
sixMonthSummary[year] = {}
try to insert the existing object with a spread-operator to include all prev months.
const sixMonthSummary = {};
// This will get data for the latest 6 months
for (let i = 0; i <= 6; i++) {
const currentDate = new Date();
const [, month, year] = new Date(
currentDate.setMonth(currentDate.getMonth() - i)
)
.toLocaleDateString("en-SG")
.split("/");
sixMonthSummary[year] = {
...sixMonthSummary[year],
[month]: {
rent: "",
income: "",
expenses: "",
},
};
}
console.log(sixMonthSummary)

It's because you're resetting the year key each iteration of the loop. Try something like
if(!sixMonthSummary[year]) {
sixMonthSummary[year] = {};
}
sixMonthSummary[year][month] = {
rent: "",
income: "",
expenses: "",
};

Related

How to filter an array based on Month comparison and get Max Date() in Angular?

I have an array of objects with a date value. I want to filter the array based on the selectedDate and get the Max date in the list of dates. In the below code, I am filtering the array based on the month. Here I get 3 values after filtering, now I want to compare those values and get the MAX Date() value.
How can I do that in Angular or ES6 way?
let selectedDate = new Date();
let array = [{
"date": "2022-08-30T23:00:00Z",
"value": "4.0"
},
{
"date": "2022-08-28T23:00:00Z",
"value": "8.0"
},
{
"date": "2022-08-25T23:00:00Z",
"value": "2.0"
},
{
"date": "2022-07-25T23:00:00Z",
"value": "2.0"
}
];
let x = array.filter(d =>
new Date(d.date).getMonth() === selectedDate.getMonth() - 1
)
console.log(x)
Expected Output:
{
"date": "2022-08-30T23:00:00Z",
"value": "4.0"
}
You need to filter not only by month, but also by year.
Please do not use new in the loop, if possible.
const array = [{"date": "2022-08-30T23:00:00Z","value": "4.0"},{"date": "2022-08-28T23:00:00Z","value": "8.0"},{"date": "2022-08-25T23:00:00Z","value": "2.0"},{"date": "2022-07-25T23:00:00Z","value": "2.0"}];
const selectedDate = '2022-09-01T06:08:58.695Z' // new Date().toISOString();
const getYearMonth = (isoDateTime) => isoDateTime.slice(0,7)
const getMax = (data, targetDate) => {
const targetYearMonth = getYearMonth(targetDate);
const filtered = data.filter(({ date }) => getYearMonth(date) === targetYearMonth);
if (filtered.length === 0) return null;
if (filtered.length === 1) return filtered.at(0);
return filtered.reduce((max, cur) => max.date.localeCompare(cur.date) < 0 ? cur : max)
};
console.log(getMax(array, '2022-07-01T06:08:58.695Z'))
console.log(getMax(array, '2022-08-01T06:08:58.695Z'))
console.log(getMax(array, '2022-09-01T06:08:58.695Z'))
.as-console-wrapper { max-height: 100% !important; top: 0 }
let yourOutput = [
{
"date": "2022-08-30T23:00:00Z",
"value": "4.0"
},
{
"date": "2022-08-28T23:00:00Z",
"value": "8.0"
},
{
"date": "2022-08-25T23:00:00Z",
"value": "2.0"
}
];
//Sort by Date
yourOutput.sort((a, b) => new Date(a) > new Date(b));
//Get First Elem
if(yourOutput.length > 0) {
console.log(yourOutput[0])
}
I think you can use reduce function afterfilter to get the max.
Assuming we have 2 variables, selectedDate and array:
let max = array
.filter(d =>
new Date(d.date).getMonth() === selectedDate.getMonth() - 1
)
.reduce((max, current) => {
if (!max) return current;
let maxDate = new Date(max.date);
let currentDate = new Date(current.date);
return maxDate > currentDate? max: current;
}, null);

Date Subtracting 1 from my day on my Web application

For some reason, I am having problems getting my date select text box to display the proper DAY in my mm/dd/yyyy section. It seems to be subtracting one off of the day when I select january 4th it will display January 3rd. If any advice could be spared it would be greatly appreciated, as I am a mere novice.
Here is some code supporting this problem, if any more information or code is needed feel free to ask.
This is my AddEntry.vue page
<script>
export default {
data() {
return {
location: "",
endUser: "",
orderNumber: "",
date: null,
application: "",
serviceTech: "",
department: "",
hours: 0,
travelHours: 0,
contactName: "",
reason: "",
};
},
computed: {
serviceEntry() {
let tmpEntry = {};
tmpEntry.location = this.location;
tmpEntry.endUser = this.endUser;
tmpEntry.orderNumber = this.orderNumber;
tmpEntry.date = this.date;
tmpEntry.application = this.application;
tmpEntry.serviceTech = this.serviceTech;
tmpEntry.department = this.department;
tmpEntry.hours = this.hours;
tmpEntry.travelHours = this.travelHours;
tmpEntry.contactName = this.contactName;
tmpEntry.reason = this.reason;
return tmpEntry;
},
},
methods: {
setServiceDate(event) {
// alert(event.target.valueAsDate.toLocaleDateString('en-US'))
this.date = event.target.valueAsDate;
// alert(this.date)
},
formatDate(date) {
var d = new Date(date),
month = "" + (d.getMonth() + 1),
day = "" + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = "0" + month;
if (day.length < 2) day = "0" + day;
return [year, month, day].join("-");
},
async submitItem() {
if (this.$store.dispatch("createServiceEntry", this.serviceEntry))
this.$router.push({
path: `/`,
});
},
},
mounted() {
this.date = new Date();
},
};
</script>

Sorting an array of objects with a variable filter

Im trying to filter my array of objects by the current month. Using animal crossing fish as an example
const fishData = {
"fish_name": "Barreleye",
"price": "15,000",
"location": "Sea",
"shadow_size": "Small",
"n_March": true,
"n_3": true,
},
{
"fish_name": "Coelacanth",
"price": "15,000",
"location": "Sea (Rainy Days)",
"shadow_size": "Largest",
"n_3": true,
}
]
var today = new Date();
var currentMonth = today.getMonth();
var fishMonth = `n_ + ${currentMonth}`;
console.log(fishMonth);
var filteredFish = fishData.filter(function(i) {
return i.fishMonth == true;
});
now by return if i put "n_3" instead of "fishMonth" the code runs fine. I've checked the "fishMonth" and it does return n_3. What would be stoping this from working?
There are unnecessay characeter in your fishMonth variable, it should be:
var fishMonth = `n_${currentMonth}`;
and you also want to read the object's key so there has to be return i[fishMonth] == true;, try:
const fishData = [{
"fish_name": "Barreleye",
"price": "15,000",
"location": "Sea",
"shadow_size": "Small",
"n_March": true,
"n_3": true,
},
{
"fish_name": "Coelacanth",
"price": "15,000",
"location": "Sea (Rainy Days)",
"shadow_size": "Largest",
"n_3": true,
}
]
var today = new Date();
var currentMonth = today.getMonth();
var fishMonth = `n_${currentMonth}`;
var filteredFish = fishData.filter(function(i) {
return i[fishMonth] == true;
});
console.log(filteredFish);
You need the right key value without space and + and the right property accessor with brackets.
You could take some more changes, for example get the month directly from the instance and return directly the value of the wanted property.
const
fishData = [{ fish_name: "Barreleye", price: "15,000", location: "Sea", shadow_size: "Small", n_March: true, n_3: true }, { fish_name: "Coelacanth", price: "15,000", location: "Sea (Rainy Days)", shadow_size: "Largest", n_3: true }],
fishMonth = `n_${(new Date).getMonth()}`,
filteredFish = fishData.filter(fish => fish[fishMonth]);
console.log(filteredFish);
Finally, you could change the whole data structure and add the month as value to the objects and use something like a month property. This allowes to use a simple comparison with the value instead of using a compound key.
const
fishData = [{ fish_name: "Barreleye", price: "15,000", location: "Sea", shadow_size: "Small", n_March: true, month: 3 }, { fish_name: "Coelacanth", price: "15,000", location: "Sea (Rainy Days)", shadow_size: "Largest", month: 3 }],
fishMonth = (new Date).getMonth(),
filteredFish = fishData.filter(({ month }) => month === fishMonth);
console.log(filteredFish);

How to group dynamic object keys in Javascript

I have an object like below
{
UserId: "",
BidderId: "",
"1stDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
}
The requirement is such that I need to group the dotted object keys and create the output as below
{
UserId: "",
BidderId: "",
1stDomestic: [
{
BidderId="",
UserId="234"
}
],
1stEmployee: [
{
CreatedDate=""
}
],
1stIndependent: [
{
UpdatedDate="",
CreatedDate=""
}
],
lstDomestic.BidderId = "",
1stDomestic.UserId="234",
1stEmployee.CreatedDate="",
1stIndependent.UpdatedDate=""
1stIndependent.CreateDate=""
}
I have tried to achieve this using couple of approaches.
Here requestedData is the object
Approach 1
for (let prop in requestedData) {
if (prop.indexOf(".") > -1) {
mainKey[prop.split(".").pop()] = requestedData[prop];
requestedData[prop.substr(0, prop.indexOf("."))] = [mainKey];
}
}
console.log(requestedData)
The above approach gives me the structure, but the array data reflects the same for all.
1stDomestic: [
{
BidderId="",
UserId="234",
CreatedDate="",
UpdatedDate=""
}
],
1stEmployee: [
{
BidderId="",
UserId="234",
CreatedDate="",
UpdatedDate=""
}
],
1stIndependent: [
{
BidderId="",
UserId="234",
CreatedDate="",
UpdatedDate=""
}
]
Approach 2
for (let prop in requestedData) {
if (prop.indexOf(".") > -1) {
arr.push({
newProp: prop.substr(0, prop.indexOf(".")), //-->1
mainKey: prop.split(".").pop(), // --> 2
value: requestedData[prop] // -->3
});
}
}
console.log(Object.assign(requestedData, groupData(arr));
groupData(arrVal) {
let key = "newProp";
return resData.reduce((previous, current) => {
previous[current[key]] && previous[current[key]].length != 0
? previous[current[key]].push(current)
: (previous[current[key]] = new Array(current));
return previous;
}, {});
}
The above approach groups the data based on the keys, but then it creates and individual arrays of object with properties as in 1,2 and 3
I expect this to be the way as mentioned above.
I am kind of now in a fix and trying to figure that out.
I am new to this forum, asking question, please bear if I somehow made this question too lengthy and intuitive.
Help would be appreciated
You can first create an object of nested objects based on the keys using reduce and then merge your original object with the nested object to get your final result:
const data = {
UserId: "",
BidderId: "",
"1stDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
};
const nested = Object.entries(data)
.filter(([k, v]) => k.includes('.'))
.reduce((acc, [k, v]) => {
const [parent, child] = k.split('.');
acc[parent] = acc[parent] || [{}];
acc[parent][0][child] = v;
return acc;
}, {});
const result = { ...data, ...nested};
console.log(result);
You can use below solution.
var requestedData = {
UserId: "",
BidderId: "",
"lstDomestic.BidderId" : "",
"lstDomestic.UserId":"234",
"lstEmployee.CreatedDate":"",
"lstIndependent.UpdatedDate":"",
"lstIndependent.CreateDate":""
}
var newData = [];
var previousKey = "";
for (let prop in requestedData) {
if (prop.indexOf(".") > -1) {
if(previousKey != prop.substr(0, prop.indexOf(".")))
{
ainKey = [];
}
previousKey = prop.substr(0, prop.indexOf("."))
mainKey[prop.split(".").pop()] = requestedData[prop];
newData[prop.substr(0, prop.indexOf("."))] = [mainKey];
}
}
console.log(newData)
you can try live working demo.
https://jsfiddle.net/cakp8z6n/4/
If you call your original object obj, this should work:
Object.keys(obj).forEach(key => {
if (key.includes('.')) {
const [base, suffix] = key.split('.');
obj[base] = obj[base] || [{}];
obj[base][0][suffix] = obj[key];
}
});
console.log(obj);
Or, if you don't want to modify the original object, but make a modified copy instead:
const obj2 = {};
Object.keys(obj).forEach(key => {
obj2[key] = obj[key];
if (key.includes('.')) {
const [base, suffix] = key.split('.');
obj2[base] = obj2[base] || [{}];
obj2[base][0][suffix] = obj[key];
}
});
let orgObj={
UserId: "",
BidderId: "",
"lstDomestic.BidderId": "",//difference 1st and Ist
"1stDomestic.UserId": "234",//difference 1st and Ist
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
};
let complexKeys = Object.keys(orgObj).filter(key=>{return key.match(/.+\..+/)})
So complexKeys now ["lstDomestic.BidderId", "1stDomestic.UserId", "1stEmployee.CreatedDate", "1stIndependent.UpdatedDate", "1stIndependent.CreateDate"]
complexKeys.forEach(eachCompleKey=>{debugger;
let firstPart= eachCompleKey.match(/^(\w+)\./)[1];
let lastPart= eachCompleKey.match(/\.(\w+)$/)[1];
if(orgObj[firstPart]==undefined){debugger;
orgObj[firstPart]=[{}];
}
orgObj[firstPart][0][lastPart]=orgObj[eachCompleKey]
})
console.log(orgObj)
Output
{
"UserId": "",
"BidderId": "",
"lstDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": "",
"lstDomestic": [
{
"BidderId": ""
}
],
"1stDomestic": [
{
"UserId": "234"
}
],
"1stEmployee": [
{
"CreatedDate": ""
}
],
"1stIndependent": [
{
"UpdatedDate": "",
"CreateDate": ""
}
]
}
You can try something like below.
let obj = {
UserId: "",
BidderId: "",
"lstDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
};
const res = Object.keys(obj).reduce((acc, mainKey) => {
let [key1, key2] = mainKey.split(".");
if (key2 && acc[key1]) {
acc[key1][0] = { ...acc[key1][0],
...{
[key2]: obj[mainKey]
}
}
} else if (key2) {
acc[key1] = [{
[key2]: obj[mainKey]
}];
} else {
acc[key1] = obj[key1];
}
return acc;
}, {})
const finalResult = { ...obj,
...res
};
console.log(finalResult)
So this code will do it, but I'm confused why you want it in this format. It seems like it would make more sense to have 1stDomestic, 1stEmployee, and 1stIndependent be their own objects rather than single element arrays. It just requires you to do more work later to access the data!
var requestedData = {
UserId: "",
BidderId: "",
"lstDomestic.BidderId" : "",
"lstDomestic.UserId":"234",
"lstEmployee.CreatedDate":"",
"lstIndependent.UpdatedDate":"",
"lstIndependent.CreateDate":""
}
let output = {};
for (let prop in requestedData) {
// Check to see if this is a "blah.thing" property
if (prop.includes(".")) {
let props = prop.split(".");
// Check to see if we've added the array already
if (output[props[0]])
output[props[0]][0][props[1]] = requestedData[prop];
else
// ES 2015 baby!
output[props[0]] = [{[props[1]]: requestedData[prop]}]
}
// If it's not then just add it normally
else
output[prop] = requestedData[prop];
}
console.log(output);

JavaScript: Compare dates in an array and sum the "price" for each month/year

I have a json file with multiple transactions with a date and a price attribute. Now I want to compare the dates and if they are in the same month and year I want to sum up the prices.
JSON:
transactions: [
{
date: "2017-11-17",
price: "28",
},
{
...
}
JavaScript:
request.onload = function() {
for(const transaction of request.response.transactions) {
let year = new Date(transaction.date).getFullYear();
let month = new Date(transaction.date).getMonth();
console.log(year + ' ' + month); // output: 2017-11 ...
}
};
I tried to loop over the json object but I struggle to find a solution to compare the dates.
Edit: Edited example with Object.assign instead of Object spread.
You'll need to use reduce to sum the prices. See comments for details.
const transactions = [{
date: "2017-11-17",
price: "28",
},
{
date: "2017-12-17",
price: "23",
},
{
date: "2017-11-17",
price: "12",
},
{
date: "2017-10-17",
price: "55",
},
{
date: "2017-11-17",
price: "09",
},
];
const sumTransactions = (transactions) => {
const summed = transactions.reduce((acc, current) => {
// Get the current date object
const date = new Date(current.date);
// Create your key/identifier
const key = `${date.getFullYear()}-${date.getMonth() + 1}`;
// Retreive the previous price from the accumulator
const previousPrice = acc[key]; // Might also return undefined
// Create your temp current price value, and be sure to deal with numbers.
let currentPrice = Number(current.price);
// If you had a previous value (and not undefined)
if (previousPrice) {
// Add it to our value
currentPrice += Number(previousPrice);
}
// Return the future accumulator value
return Object.assign(acc, {
[key]: currentPrice, // new values will overwrite same old values
})
}, {})
// Once we have all values, get the dates, and sort them (default: earlier first)
// Return an array of each value from the summed object to our sortedArray
const sortedArray = Object.keys(summed).sort().map((val) => {
return summed[val];
});
console.log("sortedArray", sortedArray);
};
sumTransactions(transactions);
I experimented a bit and came up with this solution:
var transactions = [
{
date: "2017-11-17",
price: "28",
},
{
date: "2017-12-17",
price: "22",
},
{
date: "2017-12-17",
price: "20",
}
]
var sumedUpDates = [];
var prices = [];
function isDateSumedUp(date) {
return sumedUpDates.indexOf(date.substring(0, 7)) !== -1;
}
function sumUpDate(date) {
var sum = 0;
transactions.forEach(t => {
if(t.date.substring(0, 7) === date.substring(0, 7)) {
sum += parseInt(t.price);
}
});
sumedUpDates.push(date.substring(0, 7));
prices.push(sum);
}
transactions.forEach(t => {
if(!isDateSumedUp(t.date)) {
sumUpDate(t.date);
}
});
var obj = {};
sumedUpDates.forEach((d, i) => obj[d] = prices[i]);
console.log(obj);
This solutions uses map to format your dates into year/month format for each object entry and then reduce to sum them by those separated dates.
const transactions = [
{date:"2017-11-17", price: "28",},
{date:"2017-12-17", price: "28",},
{date:"2017-11-17", price: "20",},
{date:"2017-12-17", price: "2",},
{date:"2017-11-17", price: "58",},
{date:"2017-11-17", price: "8",},
{date:"2017-10-17", price: "30",},
{date:"2018-11-17", price: "1",},
];
const mapper = single => {
let d = single.date.split('-');
let p = Number(single.price);
return { year: d[0], month: d[1], price: p };
}
const reducer = (group, current) => {
let i = group.findIndex(single => (single.year == current.year && single.month == current.month));
if (i == -1) {
return [ ...group, current ];
}
group[i].price += current.price;
return group;
};
const sumPrices = transactions.map(mapper).reduce(reducer, []);
console.log(sumPrices);
var array = [];
for (var i = 0; i < transactions.length; i++) {
var date = new Date(transactions[i].date);
var ym = date.getFullYear() + "-" + date.getMonth();
if (array[ym] == null) {
array[ym] = 0;
}
array[ym] += parseInt(transactions[i].price);
}
With this data
var transactions = [{
date: "2017-11-17",
price: "28",
},
{
date: "2017-12-17",
price: "5",
},
{
date: "2016-02-17",
price: "28",
},
{
date: "2015-11-17",
price: "25",
},
{
date: "2016-02-17",
price: "12",
},
{
date: "2017-11-17",
price: "50",
}
];
This will give you the sum of all of the year-months duplicates like this :
[
2017-10: 78,
2017-11: 5,
2016-1: 40,
2015-10: 25
]
Another solution is reduce:
var transactions = [
{date: "2017-11-17",price: "28"},
{date: "2017-12-17",price: "22"},
{date: "2017-12-17",price: "20"}
];
var result = transactions.reduce(function(acc, obj) {
var key = obj.date.substr(0,7);
acc[key] = (acc[key] || 0) + +obj.price;
return acc;
}, Object.create(null));
console.log(result);

Categories