Javascript sort function on dates not working - javascript

So I have this code -
console.log(data);
data = data.sort(function(d1,d2){
var a1= d1["date"].split('/'), b1=d2["date"].split('/');
if(a1[2]==b1[2]){
return (a1[0]==b1[0])? a1[1]-b1[1]: a1[0]-b1[0];
}
return a1[2]-b1[2];
});
console.log("DATA");
console.log(data);
with this data -
[
{ "date": "2/7/2012", "quantity: " 4"},
{ "date": "2/4/2012", "quantity: "5"},
{ "date": "2/3/2012", "quantity: "10"},
{ "date": "2/5/2012", "quantity" : "12"},
{ "date": "2/6/2012", "quantity" : "10"}
]
The two console logs show the data in the same way, or the sorting has no effect. The data coming out of the sort function is in the same order as the data going in.
Why?

Try:
data = data.sort(function(d1,d2){
return new Date(d1.date) - new Date(d2.date);
});
DD/MM/YYYY should be acceptable by Date parser, here is the spilt version.
data = data.sort(function(d1, d2){
var d1 = d1.split('/'), d2 = d2.split('/');
return new Date(d1[2], d1[0] - 1, d1[1]) - new Date(d2[2], d2[0] - 1, d2[1]);
});

Related

How to transform object to nested object

I am new in JavaScript and programming. I get data via AJAX. I want to re-generate it to get a nested object grouped by part of the data. In this case I want it grouped by year and month
Here is my data and my function:
myObj = [
{"date":'2019-06-05',"name":"abc 0"},
{"date":'2019-06-01',"name":"abc 1"},
{"date":'2019-05-25',"name":"abc 2"},
{"date":'2019-05-15',"name":"abc 3"},
{"date":'2020-06-30',"name":"abc 4"},
{"date":'2020-06-25',"name":"abc 5"},
{"date":'2020-05-28',"name":"abc 6"},
{"date":'2020-05-26',"name":"abc 7"}
];
function regenerate(data) {
var result = {
"allyears": [{}]
};
for (x = 0; x < data.length; x++) {
var year = data[x].date.slice(0, 4);
var month = data[x].date.slice(5, 7);
if (!result.allyears.months) {
result.allyears['year'] = year;
result.allyears.months = [{}];
}
if (!result.allyears.months.data) {
result.allyears.months['month'] = month;
result.allyears.months.data = [{}];
}
result.allyears.months.data[x] = data[x];
}
console.log(result);
return result;
};
regenerate(myObj);
Result I expect:
{
"allyears": [{
"year": "2019",
"months": [{
"month": "06",
"data": [{
"date": '2019-06-05',
"name": "abc 0"
},
{
"date": '2019-06-01',
"name": "abc 1"
}
]
}, {
"month": "05",
"data": [{
"date": '2019-05-25',
"name": "abc 2"
},
{
"date": '2019-05-15',
"name": "abc 3"
},
]
}]
}]
};
What am I missing in my function?
Probably not the cleverest solution, but it should do the job "beautifully".
The routine is taking the advantage of Array.reduce, where an initial accumulator (in this case an empty array) is used and, while looping the original myObj array, it checks whether:
The year element exists in the array. If it doesn't it creates it.
The month element exists in the year element. If it doesn't it creates it.
Once everything is created, it adds data to the current month.
I will add some comments to the snippet below for further explanations, the output, to me, seems okay.
const myObj = [
{"date":'2019-06-05',"name":"abc 0"},
{"date":'2019-06-01',"name":"abc 1"},
{"date":'2019-05-25',"name":"abc 2"},
{"date":'2019-05-15',"name":"abc 3"},
{"date":'2020-06-30',"name":"abc 4"},
{"date":'2020-06-25',"name":"abc 5"},
{"date":'2020-05-28',"name":"abc 6"},
{"date":'2020-05-26',"name":"abc 7"}
];
let res = {
allyears: myObj.reduce((acc, next) => {
let [year, month, day] = next.date.split('-');
// ^-- Acquire year, month and day (actually, day is not needed) from the original date string.
let yearRef = acc.find(i => i.year === year);
// ^-- checks whether the current year already exists in the array.
if (!yearRef) acc.push({year}), yearRef = acc[acc.length - 1];
// ^-- if it doesn't, it creates it and fill the above reference of it.
yearRef.months = yearRef.months || [];
// ^-- same as the year above, but with month.
let monthRef = yearRef.months.find(i => i.month === month);
if (!monthRef) yearRef.months.push({month}), monthRef = yearRef.months[yearRef.months.length - 1]// ^-- same as above, with month.
monthRef.data = (monthRef.data || []).concat(next);
// ^-- once the month element is available, add the next element to data. If data does not yet exist, init it.
return acc;
}, [])
};
console.log(res);

How to generate an array of unique objects from api?

I'm trying to disable booked times from calendar, depending on the date. My goal is to create an array, which holds objects with single date and array of booked times.
I have created an api, which outputs something like this:
"bookings": [
{
"_id": "5ce1b8792598adasf452",
"workType": "Nail polishing",
"client": "Mary Johnson",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "09:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "10:00"
}
]
I've tried using Sets, filters, but I just can't seem to wrap my head around how to implement it to my own code.
Snippet of my code:
bookedTimes: []
fetchBookedTimes() {
axios.get("http://localhost:8080/api/bookings").then(res => {
for (var i = 0; i < res.data.bookings.length; i++) {
this.bookedTimes.push({
date: moment(res.data.bookings[i].date).format("YYYY-MM-DD"),
times: [res.data.bookings[i].bookingTime.substring(0,2)]
});
}
});
}
I expect the output to be
bookedTimes: [
{
date: "2019-05-31",
times: ["09", "10"]
},
{
date: "2019-06-01",
times: ["10", "11"]
}
]
But the actual output is
bookedTimes: [
{
date: "2019-05-31",
times: ["09"]
},
{
date: "2019-05-31",
times: ["10"]
},
{
date: "2019-06-01",
times: ["10"]
},
{
date: "2019-06-01",
times: ["11"]
}
]
As per the code, the actual output is correct. You are looping the response and pushing the data to an array. If you want to group them by date, then you have to create an object and then convert it to the expected output.
var result = res.data.bookings.reduce(function (defaultValue, booking) {
var date = moment(booking.date).format("YYYY-MM-DD");
defaultValue[date] = defaultValue[date] || {date: date, times: []};
defaultValue[date].times.push(booking.bookingTime.substring(0,2));
return defaultValue;
}, {});
console.log(Object.values(result));
You can simply use reduce()
const arr = [
{
"_id": "5ce1b8792598adasf452",
"workType": "Nail polishing",
"client": "Mary Johnson",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "09:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "10:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-06-31T00:00:00.000Z",
"bookingTime": "11:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-06-31T00:00:00.000Z",
"bookingTime": "12:00"
}
]
const res = arr.reduce((ac,{date,bookingTime}) => {
ac[date] = ac[date] || {date,bookingTime:[]}
ac[date].bookingTime.push(bookingTime.slice(0,2));
return ac;
},{})
console.log(Object.values(res))
You're pushing values directly into array but you need to group them by date so you can use an object and then push values to array in the end
Here temp is used to group values by date
We check for date it exists we push the time value to times array if not we create a new property on temp
In the end we push values to this.bookedTimes array
fetchBookedTimes() {
axios.get("http://localhost:8080/api/bookings").then(res => {
let temp = {}
for (var i = 0; i < res.data.bookings.length; i++) {
let date = moment(res.data.bookings[i].date).format("YYYY-MM-DD"),
let time = [res.data.bookings[i].bookingTime.substring(0,2)]
temp[date] = temp[date] || {date: date, times:[]}
temp[date].times.push(time)
});
}
this.bookedTimes.push(Object.values(temp))
});
}
First, check if the date of already in the array. Check if 'times' already exist in 'object.times', if not, push it to the 'object.times' array.
Please see the code below.
const date = moment(res.data.bookings[i].date).format("YYYY-MM-DD");
const times = res.data.bookings[i].bookingTime.substring(0, 2);
const arrayIndex = bookedTimes.findIndex(item => item.date === date);
//Check if date already exist in array
if (arrayIndex !== -1) {
//Check if 'times' already exist in 'object.times'
if (!bookedTimes[arrayIndex].times.includes(times)) {
//Push 'times' in 'object.times'
bookedTimes[arrayIndex].times.push(times);
}
} else {
//Push a new object into the array
bookedTimes.push({
date: date,
times: [times]
});
}

Javascript: group by with aggregation

I have a simple json list like the one below
{
"myList": [
{
"endOfPeriod": 1461362400000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461535200000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461967200000,
"rate": 0.03708314
},
{
"endOfPeriod": 1461708000000,
"rate": 0.03492851
},
{
"endOfPeriod": 1461794400000,
"rate": 0.03845068
},
{
"endOfPeriod": 1461621600000,
"rate": 0.03544827
}
]
}
Where endOfPeriod is a unix epoch timestamp. All the timestamps in the example belong to the same month (April 2016), but could be some other periods.
Assuming that I have already converted this json list into an array, and each unix timestamp into a DD.MM.YYYY date (I can keep them in unix timestamp too). Is there an efficient way to create a new array with the most recent rate for grouped by month/year?
I have to write code in Javascript.
For instance:
20.04.2016 / 0.33
21.04.2016 / 0.55
14.04.2016 / 0.88
02.05.2016 / 1.33
01.05.2016 / 5.44
New array must contain:
21.04.2016 / 0.55
02.05.2016 / 1.33
Thanks for your help.
If I understand correctly, you want to extract the most recent rate for each month. I would use lodash.
_.chain(arr)
.groupBy(function(item) {
var date = new Date(item.endOfPeriod);
return date.getFullYear() + '-' + date.getMonth();
})
.map(function(group) {
return _.maxBy(group, function(item) {
return item.endOfPeriod;
});
})
.value()
We start with a list of objects in the form:
{
"endOfPeriod" : 1464818400000,
"rate" : 0.05
}
The chain() function wraps the list into a lodash object.
Then, we group elements by year and month. After the groupBy(), we have the following structure (note that getMonth() is 0-based in Javascript, hence a value of 3 corresponds to April, and so on):
{
"2016-3" : [array of objects in April 2016],
"2016-4" : [array of objects in May 2016]
...
}
Then, for each group, we take the item with maximum endOfPeriod.
Finally, value() unwraps the lodash object back into a plain Javascript array.
Here is a result without using lodash. But for me it's better not to reinvent the wheel.
const myList = [
{
"endOfPeriod": 1461362400000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461535200000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461967200000,
"rate": 0.03708314
},
{
"endOfPeriod": 1461708000000,
"rate": 0.03492851
},
{
"endOfPeriod": 1461794400000,
"rate": 0.03845068
},
{
"endOfPeriod": 1461621600000,
"rate": 0.03544827
}
];
const res = myList.reduce((prev, current) => {
const date = new Date(current.endOfPeriod);
const month = date.getMonth();
const year = date.getFullYear();
const key = `${year}-${month}`;
if (prev[key] && prev[key].endOfPeriod < current.endOfPeriod) {
prev[key] = current;
} else {
prev[key] = current;
}
return prev;
}, {});
const finalResult = Object.keys(res).map((key) => {
return {
key: res[key].rate
}
});
console.log(finalResult);

Generate a Required File using JavaScript

I need to generate a JSON file using a JAVA script , but am not getting the expected output , can you help me generating out put of this .
Expected out put :
{
"ewh5yuwe": {
"NumCopies": "1",
"NumPages": "10",
"Status": "done printing",
"Title": "demo.jpg",
"Username": "keshavka",
"date": "23:06 Feb 5, 15",
"print status": "OK",
"time": "1429036296",
"timestamp done printing": "${__time(yyyyMMddHMS)"
}
}
out put received after calling print(); function is as below:
""rYajbQx":{[object Object]}"
code:
function makeid() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 7; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
//above Code is to generate a Random variable
function test() {
var jobid = Math.random();
var jobkey = jobid;
var time = new Date().getTime()
var kes = makeid()
var joblog = {
"NumCopies": "1",
"Status": "done printing",
"Title": "demo.jpg",
"Username": "keshavka",
"date": "23:06 Feb 5, 15",
"print status": "OK",
"time": "1429036296",
"timestamp done printing": time
};
json = JSON.stringify(joblog);
console.log(joblog);
return joblog;
}
// Above code is to generate JSON
var x = test();
console.log(x);
var y = makeid();
console.log(y);
function print() {
a = ('{' + (test()) + '}');
return a;
}
The problem is that you're not returning the JSON, but the object itself.
function test() {
[...]
var json = JSON.stringify(joblog);
console.log(json);
return json;
}
Ok, I think I know what you want. You want to return an object that has a property on it with the name of the id you generate and its value set to the properties listed in the code above. The main thing I would change is how the object is created. So in your test function I would make the following changes:
var joblog = {};
joblog[kes] = {
"NumCopies":"1",
"Status": "done printing",
"Title": "demo.jpg",
"Username": "keshavka",
"date": "23:06 Feb 5, 15",
"print status": "OK",
"time": "1429036296",
"timestamp done printing": time
};
So if you generate an id of '5YhDv7n', you would get an object of type:
{
5YhDv7n:{
ObjectNumCopies: "1",
Status: "done printing",
Title: "demo.jpg",
Username: "keshavka",
date: "23:06 Feb 5, 15",
print status: "OK",
time: "1429036296",
timestamp done printing: 1435580266234
}
}
I edited the JSFiddle I made to reflect these changes.

Populate Highchart Column From JSON

I have to create a column chart in my project using Highchart. I am using $.ajax to populate this data. My current JSON data is like this :
[{
"city": "Tokyo",
"totalA": "10",
"totalB": "15"
},
{
"city": "Seoul",
"totalA": "20",
"totalB": "27"
},
{
"city": "New York",
"totalA": "29",
"totalB": "50"
}]
How to resulting JSON string look like this:
[{
"name": "city",
"data": ["Tokyo", "Seoul", "New York"]
}, {
"name": "totalA",
"data": [10, 20, 29]
}, {
"name": "totalB",
"data": [15, 27, 50]
}]
Thank you.
Assuming all the elements look the same (they all have the same fields): Live Example
// src is the source array
// Get the fields from the first element
var fields = Object.keys(src[0]);
// Map each key to...
var result = fields.map(function(field) {
// Grab data from the original source array
var data = src.reduce(function(result, el) {
// And create an array of data
return result.concat(el[field]);
}, []);
// Format it like you want
return {name: field, data: data};
});
console.log(result);
If they aren't, the code is slightly more complicated: Live Example
// Work out the fields by iterating all of the elements
// and adding the keys that weren't found yet to an array
var fields = src.reduce(function (fields, current) {
return fields.concat(Object.keys(current).filter(function (key) {
return fields.indexOf(key) === -1;
}));
}, []);
var result = fields.map(function (field) {
// Need another step here, filter out the elements
// which don't have the field we care about
var data = src.filter(function (el) {
return !!el[field];
})
// Then continue like in the example above.
.reduce(function (result, el) {
return result.concat(el[field]);
}, []);
return {
name: field,
data: data
};
});
console.log(result);

Categories