Cannot overwrite date with moment.js - javascript

I have a collection of activities and MongoDB. Activities also have a date. I'm trying to dynamically build a table with all activities saved in my collection. Therefor I want to change the format of the date with moment.js right before I send the array of JSON objects to my jade file.
I tried to make a new results array and send this one over to my jade file.
router.get('/', function(req, res, next) {
activitiesController.getActivities(function(results) {
if(!results) {
results = [];
}
for(var key in results) {
results[key].date = moment(results[key].date).format('ddd, hA');
}
res.render('index', {
activities: results
})
});
});
This is how the results array looks:
[{
"_id" : ObjectId("56fe2c0d7afcafa412ae19c2"),
"title" : "Fitnessstudios",
"category" : "Sport",
"time" : 2,
"date" : ISODate("2016-03-30T00:00:00.000Z"),
"__v" : 0
}]

Your problem is that the value you are passing to moment.js is:
ISODate("2016-03-30T00:00:00.000Z")
when it wants just the date string part:
"2016-03-30T00:00:00.000Z"
So get just the date string and pass that, the snippet below shows how to do that.
var dateString = 'ISODate("2016-03-30T00:00:00.000Z")'.replace(/^[^\"]+\"([^\"]+)\".*$/,'$1');
document.write(dateString);
moment.js will likely parse an ISO string just fine without further help, however I think it's much better to tell it the format, so you should use something like:
var dateString = results[key].date.replace(/^[^\"]+\"([^\"]+)\".*$/,'$1');
results[key].date = moment(dateString,'YYYY-MM-DDThh:mm:ss.sssZ').format('ddd, hA');
// Wed, 10AM
And you should not use for..in over an array, you may find properties other than those you expect and in a different order. Use a plain for, while or do loop or one of the looping methods like forEach, map, etc. as appropriate.

Change this:
moment(results[key].date).format('ddd, hA');
to
moment(new Date(results[key].date.toString()),moment.ISO_8601).format('ddd, hA');

Related

Read data from JSON with multiple JSON objects in order to be displayed

I have the following JSON object that contains multiple JSON objects.
I want to read and display the following elements 1) CampaignName 2) Start date 3) End date
I have written the following the following code which produces error to the browser console. So, the items are not displayed.
the produced error at the browser console is:
I assume I do not access the elements as appropriate.
How shall I do it ?
You are using the .each function that iterate over each object... each object has the properties that you need. Each of these values you are iterating over is an object and not an array
Use v.Campaign.CampaignName instead of accessing the index first
the v that you are trying to access already is the date on a single JSON object so there is no need of passing the count param. I would suggest you refactoring your code to something like:
data.forEach(({ Campaign: {CampaignName, StartDate, EndDate } }) => {
events.push({
title: CampaignName,
title: moment(StartDate),
title: moment(EndDate),
})
})

Compare date and time in Mongo

I'm writing a mongo query to show records based on the current time. However, the query returns 0 records when I try to query against date and time. Below is the query:
let now = momenttz.tz(moment(),tz).toDate();
tmpl.listSelectorFilter('scheduledVisits', {
$gte: now,
$lte: moment.utc(today, 'MM/DD/YYYY').endOf('week').toDate()
});
Note: If I set the time to zero hours, it works.
How do I change this query in order to make it work? Any help is appreciated.
Does the data you're querying against have timestamps or a dateTime object to compare? Essentially you aren't comparing the records to any time, so there is no way for mongo to know what to filter by.
I would suggest you do something like a find instead and compare to dates within the record with the appropriate date field:
example:
db.collection.find({
{ $and: [ { data.date: { $gte: now } }, { data.date: { $lte: endOfWeek } } ] }
})
also keep in mind that in mongo land you can't use functions like you would do with moment, hence why I put "endOfWeek" which would be a variable you set similar to now:
let now = momenttz.tz(moment(),tz).toDate();
let endOfWeek = moment.utc(today, 'MM/DD/YYYY').endOf('week').toDate()

Mongoose findOneAndUpdate: create and then update nested array

I have a program where I'm requesting weather data from a server, processing the data, and then saving it to an mlab account using mongoose. I'm gathering 10 years of data, but the API that I'm requesting the data from only allows about a year at a time to be requested.
I'm using findOndAndUpdate to create/update the document for each weather station, but am having trouble updating the arrays within the data object. (Probably not the best way to describe it...)
For example, here's the model:
const stnDataSchema = new Schema(
{
station: { type: String, default: null },
elevation: { type: String, default: null },
timeZone: { type: String, default: null },
dates: {},
data: {}
},
{ collection: 'stndata' },
{ runSettersOnQuery: true }
)
where the dates object looks like this:
dates: ["2007-01-01",
"2007-01-02",
"2007-01-03",
"2007-01-04",
"2007-01-05",
"2007-01-06",
"2007-01-07",
"2007-01-08",
"2007-01-09"]
and the data object like this:
"data": [
{
"maxT": [
0,
null,
4.4,
0,
-2.7,
etc.....
what I want to have happen is when I run findOneAndUpdate I want to find the document based on the station, and then append new maxT values and dates to the respective arrays. I have it working for the date array, but am running into trouble with the data array as the elements I'm updated are nested.
I tried this:
const update = {
$set: {'station': station, 'elevation': elevation, 'timeZone': timeZone},
$push: {'dates': datesTest, 'data.0.maxT': testMaxT}};
StnData.findOneAndUpdate( query, update, {upsert: true} ,
function(err, doc) {
if (err) {
console.log("error in updateStation", err)
throw new Error('error in updateStation')
}
else {
console.log('saved')
but got an output into mlab like this:
"data": {
"0": {
"maxT": [
"a",
"b",
the issue is that I get a "0" instead of an array of one element. I tried 'data[0].maxT' but nothing happens when I do that.
The issue is that the first time I run the data for a station, I want to create a new document with data object of the format in my third code block, and then on subsequent runs, once that document already exists, update the maxT array with new values. Any ideas?
You are getting this output:
"data": {
"0": {
"maxT": [
"a",
"b",
because you are upserting the document. Upserting gets a bit complicated when dealing with arrays of documents.
When updating an array, MongoDB knows that data.0 refers to the first element in the array. However, when inserting, MongoDB can't tell if it's meant to be an array or an object. So it assumes it's an object. So rather than inserting ["val"], it inserts {"0": "val"}.
Simplest Solution
Don't use an upsert. Insert a document for each new weather station then use findOndAndUpdate to push values into the arrays in the documents. As long as you insert the arrays correctly the first time, you will be able to push to them without them turning into objects.
Alternative Simple Solution if data just Contains one Object
From your question, it looks like you only have one object in data. If that is the case, you could just make the maxT array top-level, instead of being a property of a single document in an array. Then it would act just like dates.
More Complicated MongoDB 3.6 Solution
If you truly cannot do without upserts, MongoDB 3.6 introduced the filtered positional operator $[<identifier>]. You can use this operator to update specific elements in an array which match a query. Unlike the simple positional operator $, the new $[<identifier>] operator can be used to upsert as long as an exact match is used.
You can read more about this operator here: https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/
So your data objects will need to have a field which can be matched exactly on (say name). An example query would look something like this:
let query = {
_id: 'idOfDocument',
data: [{name: 'subobjectName'}] // Need this for an exact match
}
let update = {$push: {'data.$[el].maxT': testMaxT}}
let options = {upsert: true, arrayFilters: [{'el.name': 'subobjectName'}]}
StnData.findOneAndUpdate(query, update, options, callbackFn)
As you can see this adds much more complexity. It would be much easier to forget about trying to do upserts. Just do one insert then update.
Moreover mLab currently does not support MongoDB 3.6. So this method won't be viable when using mLab until 3.6 is supported.

How to create a query on a Date field in MongoDB using mongoose?

I am trying to query a collection in Mongo database, to get all record with Time field in a date range. Time is defined as Date in database.
My environment: Node.js, Express, Jade, javascript.
This is the javascript code:
var query = {};
var timeQuery = {};
timeQuery["$lt"] = new Date().toISOString();
query["Time"] = timeQuery;
console.log(query);
db.model('testruns').find(query).exec(function (err, testruns) {
console.log(testruns.length);
// doing something
});
the result printed to console:
{ Time: { '$lt': '2014-10-30T15:04:39.256Z' } }
0
The query returns 0 results (there should be more)
By the way... Running date queries from RoboMongo returns results, just the wrong ones. for example:
db.testruns.find({Time : {"$gte" : new Date("2014-10-30T15:13:37.199Z")}})
returns all records.
What I tried:
This one, that one, another one, mongoose documentation of course, and many more results from google.
Most of them give the same answer, none of them works for me. HELP!
as far I see you are not including the field to reference in the query, can you try this:
I assume your field name is 'time'
var date = new Date(); //or the date you want to compare
db.model('testruns').find({"Time":{"$lt":date}}).exec(function (err, testruns) {
console.log(testruns.length);
// doing something
});
The problem was related to a schema definition, not directly to this code. The code of the query was correct. a schema definition had this field(Time) as String, which caused MongoDB to try and find a string in a date field...

Sorting UTC dates in javascript

EDIT 4/16/2012: I solved the issue of getting the timezone abbreviated into a letter format, had to download a third party sorting method and add a few things to get the desired results. The only problem now is Daylight Savings Time handlers, but there are a bunch of subjects on that. However if anyone knows how to handle UTC Daylight Savings hanlers, please feel free to help.
Thank you everyone.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
I've made an html table that I've binded with a javscript viewmodel using knockoutjs that pulls the info from a private server usin JSON function. I'm trying to make each column sortable (click on the column header once to get everything in descending order according to that column's info; click header again to get everything in ascending, and a third time to get everything in it's original order).
PLEASE NOTE: I have searched for my problem and have seen other solutions, but nothing so far has worked for me. I'm hoping to find a solution specific towards my code.
The Javascript ViewModel.js file is basically like this:
Event(column1, column2, ...., columnN){
var self = this;
self.column1 = column1;
self.column2 = column2;
.
.
}
//Sort column2 that has the Dates (dd (day) HHMM (hours/minutes) mmm (month) yy (year) format)
self.sortColumn = "Column2"
self.sortAscending = true;
self.SortByDates = function(){
if(self.sortColumn == "Column2")
self.sortAscending = !self.sortAscending;
else{
self.sortColumn = "Column2"
self.sortAscending = true;
}
self.rows.sort(function(a,b){
if(self.sortAscending == true)
for(self.Column2 in self.rows)
return a.Column2 > b.Column2 ? 1 : a.Column2 < b.Column2 ? -1 : 0;
else
return a.Column2 < b.Column2 ? 1 : a.Column2 > b.Column2 ? -1 : 0;
});
}
//specify location of server and info and get them
function getEvents(){
$.getJSON("http://.........",
function (data){
$.each(data.d, function(i, item){
handleEvent(item)
})
}
);
}
//pushes (AKA populates) info from server into the table
function handleEvent(item){
var newEvent = new Event(item.Column1InfoFromServer,
formatJSONDate(item.Column2DateInfoFromServer), .....)
this.Model.rows.push(newEvent);
}
//Formats the date info from server into dd (day) HHMM (hours/minutes) mmm (month) yy (year)
formatJSONDate(jsonDate){
var date = new Date(parseInt(jsonDate.substr(6)));
return date.format("dd HHMM mmm yy");
}
this.Model = new ViewModel();
this.getEvents();
ko.applyBindings(this.Model);
I'm having one hell of a hard time getting the Date in its converted form (yes it HAS to be in that form --> actually, I still need to figure out how to include the time-zone abbreviation right after the 'HHMM' part based off of UTC). So lets say I have "11 1136 Apr 12" and "22 1624 Jan 12" among other dates in the table. Right now when I try sorting the table according to the dates, they don't sort appropriately. Any help is appreciated, thank you.
EDIT: To be clear, I'm trying to display the timezones in military timezone codes (timezones 'A'-'Z'). Also, the dates being taken from the server are already in UTC.
UPDATE:
I was looking at another question, and someone created a knockout grid addon:
https://github.com/ericmbarnard/KoGrid
I bet this might help you out :-)
---OLD ANSWER for nostalgia----
There are some great helper functions in the Underscore library, one of them being sort:
http://documentcloud.github.com/underscore/#sortBy
sortBy_.sortBy(list, iterator, [context]) Returns a sorted copy of
list, ranked in ascending order by the results of running each value
through iterator. Iterator may also be the string name of the property
to sort by (eg. length).
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
=> [5, 4, 6, 3, 1, 2]
I'd give this a shot, along with creating a better model for your dates. It sounds like you need to store a property which is a unique point in time, along with a text value for the user.
Well, to get numeric values for your date objects, sort by pDate.valueOf(). This will give you the # of millisecond since epoch.
However, there is an issue inside of your sort function, but I'm not sure what it is supposed to do. You can't walk an object inside of a sort function and return values like that.

Categories