How to sort Date on NeDb Database with JavaScript - javascript

How can I sort Dates like below in a NeDb Database with a JavaScript function?
This sort command in the function loaddata() does not work:
loaddata() {
this.$db.DBData.find({}).sort({ pubDate: 1 }).exec((err, docs) => {
this.Data = docs;
});
}
Examples for pubDate:
Fri, 29 Jun 2018 20:15:00 +0200
Mon, 25 Jun 2018 04:22:00 +0200
Fri, 29 Jun 2018 05:10:00 +0200
Sat, 30 Jun 2018 23:35:43 +0200
Thanks in advance!

If the dates are being stored as strings then sorting them as strings is going to be alphabetizing them by the short day. If you convert them to Date objects before sorting it should work:
loaddata() {
this.$db.DBData.find({}).exec((err, docs) => {
let newDocs = docs.map((doc)=>{
doc.pubDate = new Date(doc.puDate).valueOf();
});
newDocs.sort((a, b)=>{
return a.pubDate - b.pubDate; //you may have to switch the order
});
this.Data = newDocs;
});
}
Another solution would be to save the Date value instead of the string representation. For example the dates you gave above translate to:
[1530296100000, 1529893320000, 1530241800000, 1530394543000]
Then sorting them results in:
[1529893320000, 1530241800000, 1530296100000, 1530394543000]
Converted back that's:
["Sun Jun 24 2018 22:22:00 GMT-0400 (Eastern Daylight Time)",
"Thu Jun 28 2018 23:10:00 GMT-0400 (Eastern Daylight Time)",
"Fri Jun 29 2018 14:15:00 GMT-0400 (Eastern Daylight Time)",
"Sat Jun 30 2018 17:35:43 GMT-0400 (Eastern Daylight Time)"]
You can see how they are sorted in order now and back in their string representation. Sorry for the time zone conversion I ran this example in the console on my browser to make sure it works.

Harry Chilinguerian's answer is on the right track, but remember to return the document inside the map function. For my solution, I decided to keep the original date and instead create a different property to store the date value. Finally, I think most users would prefer reverse chronological ordering:
loaddata() {
this.$db.DBData.find({}).exec((err, docs) => {
let newDocs = docs.map((doc)=>{
doc.pubDateValue = new Date(doc.pubDate).valueOf(); // new property
return doc; // return the new document
});
newDocs.sort((a, b)=>{
return b.pubDateValue - a.pubDateValue; // reverse chronological order
});
this.Data = newDocs;
});
}

Related

How to keep unique months in array of timestamps

I want to create an array that contains unique months (August 2015, September 2015 etc.). For this I defined the following function that takes an object with timestamps as keys:
export function getUniqueMonths(exps) {
//1. get all keys from expenditures
const days = Object.keys(exps)
//2. convert key strings to timestamps
const daysInt = days.map((day) => (new Date(parseInt(day))))
//3. return only the "date portion" of the timestamp
const datePortion = daysInt.map((day) => (new Date(day.toDateString()) ))
//4. set each datePortion to 1st of month
const firstOfMonth = datePortion.map((day) => new Date(day.getFullYear(), day.getMonth(), 1) )
//5. keep only unique firstOfMonths
const uniqMonths = [...(new Set(firstOfMonth))]
return uniqMonths
}
However, this function gives me an array like this:
[Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Tue Sep 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), ...]
I thought getting the date portion of the timestamp (step 3) and setting all dates to first of month (step 4) would do the trick. But I still have duplicates in my array.
What am I missing?
I think you might be overengineering things :) Something like
function getUniqueMonths(exps) {
const uniqueMonths = new Set();
Object.keys(exps).forEach((timestamp) => {
const date = new Date(parseInt(timestamp)); // expected to be milliseconds since 1/1/1970
uniqueMonths.add(`${date.getFullYear()}-${date.getMonth()}`);
});
return uniqueMonths;
}
should get you a Set of unique months in the form of ['2017-12', '2018-0', ...] (zero-based months as is the JavaScript standard).
If you need Date objects, those are trivial to "rehydrate".
Two Date objects are not the same object, even if they contain the same timestamp.
Instead, try:
//3. keep the year-month portion of the date
const yearMonths = daysInt.map(day => day.getFullYear()+"-"+day.getMonth());
Then you can skip 4 and just get the unique year-months from there. These will be returned as "2015-7" for August 2015, for example.

Why .setUTCHours returns different results?

I have the following function which should read time in UTC and return in local time, and sometimes it adds 2 hours(correctly) and sometimes 4 hours. Why is that? What can be the reason?
value = time in UTC
toLocalDate(value) {
let string = new Date(value);
let date = new Date();
date.setUTCFullYear(string.getFullYear(), string.getMonth(), string.getDate());
date.setUTCHours(string.getHours(), string.getMinutes(), string.getSeconds(), 0);
return date;
}
Example data:
Value: 2017-08-23T06:00:00
Expected output: Wed Aug 23 2017 08:00:00 GMT+0200 (Central European Daylight Time)
Output: Wed Aug 23 2017 10:00:00 GMT+0200 (Central European Daylight Time)
On some devices(like my phone or computer) it returns the expected output.
On my friend's device(mobile) it returns the second output.

Javascript loop and insert new object

I with ajax get this data:
[{"id":125,"price":225,"start":"Tue, 26 Apr 2016 00:00:00 +0000","user_id":8},{"id":124,"price":200,"start":"Wed, 27 Apr 2016 00:00:00 +0000","user_id":8},{"id":121,"price":67,"start":"Sat, 23 Apr 2016 00:00:00 +0000","user_id":8},{"id":114,"price":45,"start":"Sun, 08 May 2016 00:00:00 +0000","user_id":9},{"id":113,"price":55,"start":"Sun, 24 Apr 2016 00:00:00 +0000","user_id":8},{"id":111,"price":55,"start":"Wed, 01 Jun 2016 00:00:00 +0000","user_id":11},{"id":110,"price":53,"start":"Fri, 03 Jun 2016 00:00:00 +0000","user_id":8},{"id":107,"price":53,"start":"Wed, 03 Aug 2016 00:00:00 +0000","user_id":8},{"id":106,"price":55,"start":"Mon, 01 Aug 2016 00:00:00 +0000","user_id":8},{"id":105,"price":53,"start":"Tue, 16 Aug 2016 00:00:00 +0000","user_id":8},{"id":104,"price":55,"start":"Thu, 21 Apr 2016 00:00:00 +0000","user_id":11},{"id":101,"price":57,"start":"Wed, 17 Aug 2016 00:00:00 +0000","user_id":8}]
so as you can see there is start data.
I also have:
var start = '04/17/2016 12:00 am';
var end = '09/20/2016 12:01 am';
Now I need to make loop day by day from start to end, check if day(date) excist into json and if not add new data into json :
{"id":0,"price":100,"start":"DATE","user_id":0}
What is the best way to do that?
UPDATE:
I create one new with dates from start to end but now I need to put json into new array: http://jsbin.com/qekijumobe/edit?js,output
My another answer had a fault in there, this is what I came up after it:
First, create a foreach loop, wich loops trough all of the objects inside the array
for (var obj of objArray) {} //Use "of" instead of "in" tk get the values and not the indices
Then, inside this loop, check every field of the objects, if they're the same, abd if they're, then break out the loop, else, if there's no matching object, push it in the array.
function isInArray(yourObj) {
for (var obj of objArray) {
if (obj.id == yourObj.id && obj.start == yourObj.start && obj.price == yourObj.price && obj.user_id == yourObj.user_id)
return true;
}
return false;
}

Array Of JS Dates How To Group By Days

I'm trying to figure out the most optimal and with as minimum amount of loops way to group my array of js dates objects from this: (Take a note this is browser console output it's actully real JS dates like new Date())
[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 23:00:00 GMT+0200 (Central Europe Daylight Time)]
to oragnized array with each date of the same day inside a "chunk" so I can display it on the UI "Aug 08" and show 2 or how many dates inside that day.
for example:
[{day: 'Aug 08', times:[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time)]}]
My current way I thought about doing it was
var startDays = _.map(occurences, function (date) {
return moment(date).startOf('day').format();
});
After that to get unique days:
_.uniq(startDays, true)
and after I got the unique days another loop to add the same day to this group as you can see by now you might see why I don't like it and this is why I would love to get some smart help because nothing gets to my head with this. Thank you.
Underscore has the _.groupBy function which should do exactly what you want:
var groups = _.groupBy(occurences, function (date) {
return moment(date).startOf('day').format();
});
This will return an object where each key is a day and the value an array containing all the occurrences for that day.
To transform the object into an array of the same form as in the question you could use map:
var result = _.map(groups, function(group, day){
return {
day: day,
times: group
}
});
To group, map and sort you could do something like:
var occurrenceDay = function(occurrence){
return moment(occurrence).startOf('day').format();
};
var groupToDay = function(group, day){
return {
day: day,
times: group
}
};
var result = _.chain(occurences)
.groupBy(occurrenceDay)
.map(groupToDay)
.sortBy('day')
.value();
Presuming your data is actually strings, I don't know why you think you need either of those libraries. You are just grouping strings based on substrings.
ES5 introduced reduce, which is great for accumulating things:
A helper to create an array of dates:
// Generate a dates array given a start date and how many to create:
function genDates(startDate, count) {
var d = new Date(+startDate),
dates = [d];
for (var i=0; i<count; i++) {
d = new Date(+d);
d.setHours(d.getHours() + 10);
dates.push(d);
}
return dates;
}
This answer originally dealt with strings, modified to work with Dates:
// Generate date key 'MMM dd'
// Replaces use of moment.js
function getDateKey(date) {
var d = date.getDate();
var m = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
return m[date.getMonth()] + ' ' + ((d<10?'0':'') + d);
}
// Generate an array in format [{day:'MMM dd', times:[d0, d1, ...]}, ...]
// Replaces use of underscore.js
var obj = dates.reduce(function(acc, d) {
var p = getDateKey(d)
if (!acc[0].hasOwnProperty(p)) acc[0][p] = [];
acc[0][p].push(d);
return acc;
},[{}])
.reduce(function(acc, v){
Object.keys(v).forEach(function(k){acc.push({day:k, times:v[k]})});
return acc;
},[]);
console.log(JSON.stringify(obj));
If optimal performance is the key, the above is 20 times faster than the underscore + Moment solution for an array of 5 to 100 dates. To make it faster, remove all use of iterators and libraries and use a single function with for loops. Note that the above is only one line of code longer than the solution using Moment.js and underscore.js.
If you need to grouping also by year or (and) month with day - I recommend to use my solution.
In answers above if you'll get different month or year with the same day - your grouping will be incorrect.
Look at the good solution:
_.groupBy(arrayOfDates, function (el) {
return (el.getFullYear() + '|y|') + (el.getMonth() + '|m|') + (el.getDate() + '|d|');
});
What I do here? Just create an unique keys for each date, which includes: year, month and day. And then I group an array by this unique key.
result
Why do need this optimization? If your array is not large enoguh than you probably don't need to optimize your algorithm.
I am not familiar with the given js libraries, but you can group your array by days with one loop. But you need to somehow determine the current day in the array and then create corresponding js object with a day-field and a times-array field and then add this object to your resulting array.
It will be much faster if you presort your array before implementing this algorithm.

Compare dates issue - javascript

I need to compare dates in javascript.
After attempt many ways...
I choose:
var endDate = new Date(secondDate.getYear(), secondDate.getMonth(), secondDate.getDate(), 0, 0, 0,0);
var startDate = new Date(firstDate.getYear(), firstDate.getMonth(), firstDate.getDate(), 0, 0, 0, 0);
if (endDate.getTime() >= startDate.getTime()) {
isValid = true;
}
else {
isValid = false;
}
In my situation:
---startDate = Tue Apr 01 1997 00:00:00 GMT+0200 (Jerusalem Standard Time) (i.e, 01/04/1997)
---endDate = Thu Jul 26 114 00:00:00 GMT+0200 (Jerusalem Standard Time) (i.e, 26/07/2014)
You see? startDate is small then endDate, right?
But:
---endDate.getTime() returns: -58551904800000
---startTime.getTime() returns: 859845600000
so, endDate.getTime() >= startDate.getTime() returns false...
In other situation, it works well:
---startDate: Sat Jul 21 114 00:00:00 GMT+0200 (Jerusalem Standard Time) (i.e, 21/07/2014)
---endDate: Sat Jul 28 114 00:00:00 GMT+0200 (Jerusalem Standard Time) (i.e, 28/07/2014)
---startDate.getTime() returns -58552336800000
---endDate.getTime() returns -58551732000000
so, endDate.getTime() >= startDate.getTime() returns true...
It seems like that javascript functions have another behavior for dates after year 2000.
What should I do? which code will be match to all of the optional situations?
Thanks.
Yeah like ghusse said, there is a problem with your end time if you fixed it so it was 2014 you would get a result such as 1406329200000 instead of -58551904800000
I found a solution, after I read Josh and ghusse answers and advice:
Use getFullYear(), instead getYear(), and all will work O.K.
Apparently, you have a problem with your end dates :
Thu Jul 26 114 00:00:00 GMT+0200
Does not mean 21/07/2014 but 21/07/114
According to the doc, here are 2 correct ways of creating your date:
var endDate = new Date(21, 6, 2014);
// Or a string corresponding to a version of ISO8601
var endDate = new Date('2014-07-21T00:00:00z+3');

Categories

Resources