Querying javascript date object in mongodb - javascript

I have a Keystone.js blog and I want to add blog archives similar to Wordpress /archive/year/month. I added some extra date fields to the post object but I feel there is a way to do this using the published date.
Right now archive year is just '2014' and archive month is '06', while the '-publishedDate' value would be something like "publishedDate" : Date( 1355644800000 ). Is there a way to write a function in the query to parse the date as a JS date object then match the values?
// Load the posts
view.on('init', function(next) {
var q = keystone.list('Post').paginate({
page: req.query.page || 1,
perPage: 10,
maxPages: 10
})
.where('state', 'published')
.sort('-publishedDate')
.populate('author categories');
if (locals.data.category) {
q.where('categories').in([locals.data.category]);
}
// If archive section, filter by year and month
if (locals.data.archiveYear && locals.data.archiveMonth) {
q.where('-publishedDate',locals.data.archiveYear);
q.where('-publishedDate',locals.data.archiveMonth);
}
q.exec(function(err, results) {
locals.data.posts = results;
next(err);
});
});

Using moment.js similar code than user1572796
if (locals.filters.year) {
var start = moment().year(locals.filters.year).month(locals.filters.month).startOf('month');
var end = moment().year(locals.filters.year).month(locals.filters.month).endOf('month');
q.where('publishedDate', { $gt: start, $lt: end });
}

This seems to work:
// Load the posts
view.on('init', function(next) {
var q = keystone.list('Post').paginate({
page: req.query.page || 1,
perPage: 10,
maxPages: 10
})
.where('state', 'published')
.sort('-publishedDate')
.populate('author categories');
if (locals.data.category) {
q.where('categories').in([locals.data.category]);
}
function daysInMonth(month,year) {
return new Date(year, month, 0).getDate();
}
if (locals.filters.year && locals.filters.month) {
var postMonth = locals.filters.month - 1;
var start = new Date(locals.filters.year, postMonth, 1);
var end = new Date(locals.filters.year, postMonth, daysInMonth(locals.filters.month, locals.filters.year));
q.find({publishedDate: { $gte: start, $lt: end }});
}
q.exec(function(err, results) {
locals.data.posts = results;
next(err);
});

Related

To sort array based on startdtate and present job or no

I am making a dynamic portfolio for myself using VueJS.
I created a way to update experiences and order it based on currently ongoing jobs showing first sorted in ascending order meaning a job with start date May 2021 will show first and then March 2021 (both being present).
Next, if I set an end date for the job, it should update and place the current jobs in the front which isn't happening.
Algorithm:
newExp() {
this.editableExperience.sort((a,b) => {
a = a.period.split(' - ');
b = b.period.split(' - ');
let aStartDate = a[0];
let aEndDate = a[1];
let bStartDate = b[0];
let bEndDate = b[1];
if (aEndDate == 'Present' && bEndDate == 'Present') {
return new Date(bStartDate) - new Date(aStartDate);
} else if (aEndDate == 'Present') {
return a;
} else if (bEndDate == 'Present') {
return b;
} else {
return new Date(bStartDate) - new Date(aStartDate);
}
})
this.experience = this.editableExperience;
}
editableExperience is an array of experiences: (I have added only required information)
editableExperience = [{period: 'May 2021 - Present'}, {period: 'November 2020 - Present'}, {period: 'January 2021 - March 2021'}, {period: 'March 2018 - July 2020'}]
Exact issue situation:
Setting the third element to present job brings it to position 2 but giving it an end date again does not send it to position 3 again.
Setting the last element to present does not bring it in front of the non-present jobs.
Your compare function is returning a string or a number while the compare function should return either 1, 0 or -1 as per the MDN docs.
I have made changes to your code below:
newExp() {
this.editableExperience.sort((a,b) => {
a = a.period.split(' - ');
b = b.period.split(' - ');
let aStartDate = a[0];
let aEndDate = a[1];
let bStartDate = b[0];
let bEndDate = b[1];
if (aEndDate == 'Present' && bEndDate == 'Present') {
return (new Date(bStartDate) - new Date(aStartDate)) > 1 ? 1 : -1;
} else if (aEndDate == 'Present') {
return -1;
} else if (bEndDate == 'Present') {
return 1;
} else {
return (new Date(bStartDate) - new Date(aStartDate)) > 1 ? 1 : -1;
}
});
this.experience = this.editableExperience;
}
The view model is a little bit mixed with data model, I would suggest to keep a clean data model which hold the original values, it is good for processing like sort. then a a computed property as view model which is depend on the data model.
data: () => ({
editableExperience: [
{start: 202105, end: 999999},
{start: 202011, end: 999999},
{start: 202101, end: 202103},
{start: 201803, end: 202107},
],
}),
then the sorting will looks like:
this.editableExperience.sort((a,b) => {
return b['end'] === a['end']? b['start'] - a['start'] : b['end'] - a['end']
})
for your view(display)
computed: {
viewExperiences() {
const ve = []
for(const e of this.editableExperience) {
ve.push(this.getExperienceDisplay(e))
}
return ve
}
},
methods: {
formatExperienceDate(dateInt) {
if(dateInt === 999999) return 'Present'
const dateStr = dateInt.toString()
const date = new Date(dateStr.substring(0, 4) + '-' + dateStr.substring(4, 6))
return date.toLocaleDateString("en-US", {year: 'numeric', month: 'long'})
},
getExperienceDisplay(exp) {
const startDate = this.formatExperienceDate(exp['start'])
const endDate = this.formatExperienceDate(exp['end'])
return `${startDate} - ${endDate}`
},
}

in JavaScript, why value is defined inside scope. but undefined outside scope?

I'm trying to calculate the amount of sign-ups of each day of the current month, and send that data
to the Statistics page, where I display that data in a chart using Chart.js.
the data initialized well insides the query's scope, however I "lose" it outside of the scope.
EDIT - I extended my code so maybe there's some information relevant to my problem.
Here is my code:
async function getSignUps() {
const query = { createAt: { $gt: date.getFirstDateOfMonth(), $lt: new Date() } };
const projection = { createAt: 1, _id: 0 }; //can be added to find()
var signUps = new Array(date.getDaysInMonth()).fill(0); //create empty array of days in current month
Contractor_Users_Collection.find(query).project(projection).toArray(function (err, result) {
if (err) throw err;
// manipulte data to create array that the index indicates the day of month
// the value indicates the amount of signups per that day of the month
for (let i = 0, d = date.getFirstDateOfMonth(); i < result.length; i++, d.setDate(d.getDate() + 1)) {
nextDate = new Date(d.getDate() + 1);
if (d <= result[i]['createAt'] <= nextDate) {
day = result[i]['createAt'].getDate() - 1;
++signUps[day];
}
}
console.log('*****');
console.log('signUps inside find : ' + signUps);
console.log('*****');
})
console.log('*****');
console.log('signUps outside find : ' + signUps);
console.log('*****');
return signUps;
};
router.get("/statistics",async (req, res) => {
const signUps = await getSignUps();
console.log('*****');
console.log('signUps :' + signUps);
console.log('*****');
res.status(200).render("statistics", { signUps: signUps });
});
Here's the output :
*****
signUps outside find : 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
*****
*****
signUps :0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
*****
*****
signUps inside find : 1,3,3,5,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
*****
I found the solution, hope it will help to others...
async function getSignUps() {
const query = { createAt: { $gt: date.getFirstDateOfMonth(), $lt: new Date() } };
const projection = { createAt: 1, _id: 0 }; //can be added to find()
var signUps = new Array(date.getDaysInMonth()).fill(0); //create empty array of days in current month
try {
let result = Contractor_Users_Collection.find(query).project(projection)
result = await result.toArray()
// manipulte data to create array that the index indicates the day of month
// the value indicates the amount of signups per that day of the month
for (let i = 0, d = date.getFirstDateOfMonth(); i < result.length; i++, d.setDate(d.getDate() + 1)) {
nextDate = new Date(d.getDate() + 1);
if (d <= result[i]['createAt'] <= nextDate) {
day = result[i]['createAt'].getDate() - 1;
++signUps[day];
}
}
return signUps;
} catch (error) {
console.error(error)
throw error
}
};

Find available days within a date range

Let's say there's a system that shows date availability for events. We have a main date range where all events go. Events can be date ranges themselves too.
Example:
[Date X]========================================[Date Y]
[A]=====[A] [B]=====[B][C]=====[C]
[ Event A ][ Open ][ Event B ][ Event C ]
Where Date X and Date Y are the main date range where events go. And A,B, and C are events that have been scheduled.
How can I efficiently retrieve the open date range?
Example 2:
var rangeStart = new Date("04-01-2016");
var rangeEnd = new Date("04-31-2016");
var eventAStart = new Date("04-01-2016");
var eventAEnd = new Date("04-06-2016");
var eventBStart = new Date("04-15-2016");
var eventBEnd = new Date("04-30-2016");
I need to return something like:
var availableRangeStart = "04-07-2015";
var availableRangeEnd = "04-14-2016";
because these are the dates in the main range that are not overlapped by "event" ranges.
To be exact on what I am trying to do:
My app is a trip planner where the user sets the dates for their trip and then adds different destinations to that trip that have their own dates. (User is going on a trip to Europe April 1st to April 30th, they will be in Paris on April 1st to April 6, then they will be in London April 15th to April 30th). But the user has not planned anything from April 7th to April 14th. I am trying to return these dates so that when they add a new destination, the dates are pre-filled.
I just give you an algorithm because the final implementation depends of your code.
var aprilAvailableDays = [true, true, true, etc...] // a boolean for each day
aprilEvents.forEach(function (event) {
for (var i = event.startDay; i <= event.endDay; i++) {
aprilAvailableDays[i] = false;
}
});
Here is a solution that returns from/to periods that are free:
// Helper function
function addDays(date, days) {
return new Date(date.getTime() + days * 24*60*60*1000);
}
// Main function
function gaps(period, events) {
events = events.slice(0).filter(function (a) {
// Exclude events which are outside the main period
return a.to >= period.from && a.from <= period.to;
}).sort(function (a, b) {
// Sort events by their starting date
return a.from - b.from;
});
var result = events.reduce(function (result, curr) {
if (curr.from - result.free > 0) {
// gap found
result.gaps.push({
from: result.free,
to: addDays(curr.from, -1)
});
}
if (curr.to - result.free >= 0) {
// first free day is after this event
result.free = addDays(curr.to, 1)
}
return result;
}, { gaps: [], free: period.from } );
// Potentially add gap between last event end period-end
if (period.to - result.free >= 0) {
result.gaps.push({
from: result.free,
to: period.to
});
}
return result.gaps;
}
// Sample data:
var period = {
from: new Date('2016-01-01'),
to: new Date('2016-12-31')
};
var events = [
{ from: new Date('2016-02-01'), to: new Date('2016-02-29') },
{ from: new Date('2016-03-01'), to: new Date('2016-03-15') },
{ from: new Date('2016-04-16'), to: new Date('2016-04-30') },
];
// Call to function
var res = gaps(period, events);
// Output in snippet
document.write('<pre>' + JSON.stringify(res, null, 4));

NODE.JS: FATAL ERROR- JS Allocation failed - process out of memory, while parsing large json objects

I am trying to parse and add into mongodb database some data that am getting from an API. I want to get all the data for every user from specific time till today.
So what I am doing is, I am retrieving for each user data for 5 days for each iteration, so its like 2-3 month data seperating into 5 days.
For some reason I am getting this error with the Allocation Failer - Process out of memory.
Seems like I get this error at the time when I arrive at a particular user, cz he seems having more data than others.
I did tried this command when running the script: node --max-old-space-size=4028 worksnap.js.
My code looks like this:
var currentMonth = new Date();
var startDate = new Date("February 1, 2016 00:00:00"); //Start from February
var counter = 1;
while (startDate.getMonth() <= currentMonth.getMonth()) {
//todo:: look if u have to increaze the start time, due the previous end time becomes start time it can take the same time time entries (have to be reviewd and make sure)....
var from = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 5);
var to = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(from, to);
}
function getTimeEntriesFromWorksnap(error, response, body) {
//console.log(response.statusCode);
if (!error && response.statusCode == 200) {
parser.parseString(body, function (err, results) {
var json_string = JSON.stringify(results.time_entries);
var timeEntries = JSON.parse(json_string);
_.forEach(timeEntries, function (timeEntry) {
_.forEach(timeEntry, function (item) {
saveTimeEntry(item);
});
});
});
}
}
function saveTimeEntry(item) {
Student.findOne({
'worksnap.user.user_id': item.user_id[0]
})
.populate('user')
.exec(function (err, student) {
if (err) {
throw err;
}
student.timeEntries.push(item);
student.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('item inserted...');
}
});
});
}
function iterateThruAllStudents(from, to) {
Student.find({status: 'student'})
.populate('user')
.exec(function (err, students) {
if (err) {
throw err;
}
_.forEach(students, function (student, i) {
if (student.worksnap.user != null) {
setTimeout(function () {
var options = {
url: 'https://api.worksnaps.com/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to,
headers: {
'Authorization': 'Basic bGhNSVwJkVUFasSxx2loOFVyZkFyOENEZEsdxxxCdUlHdElWMHo0czo='
}
};
request(options, getTimeEntriesFromWorksnap);
}, 5000 * i);
}
});
});
}
Anyone knows what I am doing wrong here?
This is more a comment, as it does not contain a solution.
There are two things that looks fishy:
One problem is with:
while (startDate.getMonth() <= currentMonth.getMonth()) {
//todo:: look if u have to increaze the start time, due the previous end time becomes start time it can take the same time time entries (have to be reviewd and make sure)....
var from = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 5);
var to = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(from, to);
}
You don't wait until you process the data of one student, but you request the data of all students in parallel.
A similar problem is the setTimeout, because depending on the execution time your code needs to hold the data of multiple requests in memory.
You should use something like async or Promise to solve asynchrone loops.

Save DateTime in a way that you can query in Azure Mobile Services (Javascript)

I want to save a DateTime value to an Azure Mobile Services backend (javascript), but if you save it as DateTime you aren't able to query on that date. The reason I want to do that is because I want to retrieve all items that are within a certain date range. I've tried to save them as ticks, but this also doens't work because the numeric value is to large.
Does anyone have an idea?
That's not correct - if you save a DateTime (date) value in the JS backend you can query based on that date. All relational operations (>=, <=, <, >, ==, !=) work find with date values.
For example, in this JS code below (for a service with a table called so), it can insert 4 dates, and send a range query that would return the two middle ones.
<html>
<head>
<title>Test site</title>
<script src="http://ajax.aspnetcdn.com/ajax/mobileservices/MobileServices.Web-1.2.5.min.js"></script>
</head>
<body>
<h1>Playing with Azure</h1>
<button onclick="insertData();">Insert data</button>
<button onclick="readData();">read data</button>
<ul id='results'></ul>
<script type="text/javascript">
var client = new WindowsAzure.MobileServiceClient(
"https://SERVICENAME.azure-mobile.net/",
"APPLICATIONKEY"
);
var table = client.getTable("so");
function handleError(err) {
addLog('Error: ' + err);
}
function addLog(text) {
var ul = document.getElementById('results');
var li = document.createElement('li');
li.appendChild(document.createTextNode(text));
ul.appendChild(li);
}
function insertData() {
table.insert({ myfield: 12, date: new Date(2014, 11, 1) }).then(function() {
addLog('Inserted data in December');
table.insert({ myfield: 11, date: new Date(2014, 10, 1) }).then(function() {
addLog('Inserted data in November');
table.insert({ myfield: 10, date: new Date(2014, 9, 1) }).then(function() {
addLog('Inserted data in October');
table.insert({ myfield: 9, date: new Date(2014, 8, 1) }).then(function() {
addLog('Inserted data in Setember');
}, handleError);
}, handleError);
}, handleError);
}, handleError);
}
function readData() {
var firstDate = new Date(2014, 8, 15);
var lastDate = new Date(2014, 10, 15);
table.where(function(firstDate, lastDate) {
return this.date >= firstDate && this.date <= lastDate;
}, firstDate, lastDate).read().done(function(results) {
addLog('Results.length: ' + results.length);
for (var i = 0; i < results.length; i++) {
addLog('Results[' + i + ']: ' + JSON.stringify(results[i]));
}
}, handleError);
}
</script>
</body>
</html>
A similar code can be written for a managed client as well. Haven't compiled it (written in notepad), but it would look somewhat like the code below:
private static MobileServiceClient client = new MobileServiceClient(
"https://SERVICENAME.azure-mobile.net", "APPLICATION_KEY");
private static IMobileServiceTable<MyType> table = client.GetTable<MyType>();
private async void InsertData_Click(object sender, EventArgs args) {
for (int month = 12; month >= 9; month--) {
var date = new DateTime(2014, month, 1, 0, 0, 0, DateTimeKind.UTC);
await table.InsertAsync(new MyType { date = date, myfield = month });
}
}
private async void ReadData_Click(object sender, EventArgs args) {
var firstDate = new DateTime(2014, 9, 15, 0, 0, 0, DateTimeKind.UTC);
var lastDate = new DateTime(2014, 11, 15, 0, 0, 0, DateTimeKind.UTC);
var items = await table
.Where(t => t.date >= firstTime && t.date <= lastTime)
.ToListAsync();
foreach (var item in items) {
AddLog("Read item: " + item);
}
}
public class MyType {
public string id { get; set; }
public DateTime date { get; set; }
public int myfield { get; set; }
}

Categories

Resources