Querying by date, regardless time part - node.js

I want to show my blog posts, paginated by creation date. I will have a page for 5 posts written in 2012-10-01, a page for 11 posts written in 2012-10-03 and no page at all for 2012-10-02 (no posts written)
Each post document is stored with a creation date which is a datetime value, here's a mongoose snippet:
var postSchema = new Schema({
url: String,
creationDate: {type: Date, default: Date.now},
contenuto: String,
});
so it will have something like 2012-10-01 18:45:03... know what I mean.
In my code, I will create a
var searchDate = new Date(yy,mm,dd);
How can I use that for querying the posts collection, without considering the "time part" of creationDate?
I'm not sure this would always work:
Post.find({ creationDate:dataRicerca })

As per this post;
How do I resolve a year/month/day date to a more specific date with time data in MongoDB?
you can store the data separately (as well as the full date) in your schema for easier searching. You could also do this;
Post.find({Posted:{$gt: Date("2012-10-01"), $lt:Date("2012-10-02")}})
(updated to use Date() rather than ISODate() for better compatibility)

Related

Proper way of updating average rating for a review system using Mongoose

I'm currently learning some backend stuff using an Udemy course and I have an example website that lets you add campgrounds (campground name, picture, description, etc.) and review them. I'm using the Express framework for Node.js, and Mongoose to access the database.
My campground schema looks like:
const campgroundSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
price: String,
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
],
rating: {type: Number, default: 0}
});
And my comment/review schema looks like:
const commentSchema = new mongoose.Schema({
text: String,
rating: {
type: Number,
min: 1,
max: 5,
validate: {validator: Number.isInteger}
},
campground: {type: mongoose.Schema.Types.ObjectId, ref: "Campground"}
});
Campgrounds and Comments also have references to a User but I've left that out for simplicity.
I'm looking to know the best practice for updating and displaying the campground average rating.
The method used by the tutorial I'm following is to recalculate the average rating each time a comment is added, changed, or deleted. Here's how it would work for a new comment:
Campground.findById(campgroundId).populate("comments").exec(function(err, campground) {
Comment.create(newComment, function(err, comment) {
campground.comments.push(comment);
campground.rating = calculateRating(campground.comments);
campground.save();
});
});
"calculateRating" iterates through the comment array, gets the total sum, and returns the sum divided by the number of comments.
My gut instinct tells me that there should be a way to make the "rating" field of Campground perform the functionality of the "calculateRating" function, so that I don't have to update the rating every time a comment is added, changed, or removed. I've been poking around documentation for a while now, but since I'm pretty new to Mongoose and databases in general, I'm a bit lost on how to proceed.
In summary: I want to add functionality to my Campground model so that when I access its rating, it automatically accesses each comment referenced in the comments array, sums up their ratings, and returns the average.
My apologies if any of my terminology is incorrect. Any tips on how I would go about achieving this would be very much appreciated!
Love,
Cal
I think what you are trying to do is get a virtual property of the document that gets the average rating but it does not get persisted to the mongo database.
according to mongoosejs :- Virtuals are document properties that you can get and set but that do not get persisted to MongoDB. They are set on the schema.
You can do this:
CampgroundSchema.virtual('averageRating').get(function() {
let ratings = [];
this.comments.forEach((comment) => ratings.push(comment.rating));
return (ratings.reduce((a,b)=>a+b)/ratings.length).toFixed(2);
});
After that on your view engine after finding campgrounds or a campground, all you need to call is ; campground.averageRating;
Read more here : https://mongoosejs.com/docs/guide.html#virtuals
also note that you can not make any type of query on virtual properties.

Passing current time to Mongoose query

I've run into problem. I made field in my Mongoose schema with type "Date":
...
timeOfPassingQuestion: Date,
...
Now, I want to pass current time in hours, minutes, seconds and miliseconds and save it into that field. How should I format my Node variable so I can pass it without errors?
Edit: Also, I forgot to say that I wanna later see how much time user spent answering question by subtracting current time and time that I pulled from DB, timeOfPassingQuestion field.
This is the syntax to create a schema that supports a date field:
// Schema
{ //...
someDate: Date,
}
// date object that you can use whenever you decide to set it
var dateObj = new Date();
This will create a JavaScript date object that you can then pass into your Mongoose object for the date field.
Or, if you will always want it on creation, put it directly in your mongoose schema
{ //...
createdDate: { type: Date, default: Date.now },
}
In order to compare the time in the future, I suggest you use moment.js, then you can query the time difference like so:
moment(Model.createdDate).fromNow();
Sources:
Mongoose Schema
Moment.js fromNow

Reporting in mongodb

I have report generating in my first node application. I used mongodb and express. I have three collections: salary rule, Leave and Employee. I want to generate employees salary by using these collections.
I found phantomjs to export pdf. I used ejs template to generate html.
I got json values from the following scenario.
find Salary rule
find All Employees
find all Leaves by date range.
Match employees and leaves by employee id and calculate the salary.
put the result json into the array and generate html by ejs
export html to pdf by using phantomjs.
I am confused that this scenario could be hit performance and error-prone. I cannot find any suitable examples for exporting in node and mongodb.
My question is-
Is it bad idea to use mongodb in this scenario or is it normal flow?
Or do I need to change my mongodb collection schema?
Leave
var schema = new mongoose.Schema({
date: { type: Date, default: Date.now },
description: String,
type: String, // paid or unpaid
empName : String,
empId : String
});
Employee
var schema = new mongoose.Schema({
id: String,
name: String,
basicSalary: Number,
active: Boolean
});
Salary Rule
var schema = new mongoose.Schema({
totalHoliday: Number,
overtimeFee: Number,
unpaidLeaveFee: Number
});
IMO looks like exporting your data to a Relational Database could be easy to generate the report.
BUT if you still want to do this with MongoDB you could do a mapReduce.
https://docs.mongodb.com/manual/reference/method/db.collection.mapReduce/
your last two steps are the same but change the way that you get the data.

MongoDB date index

I am using node.js and mongodb for my small application and I want to index my document by date object. For Example
var MySchema = new Schema({
created_at: { type: Date, default: Date.now }
});
myschema.index({created_at: -1});
But how I understand, each object will have nearly unique create_id field. Wouldit work well ? and would this method give me effect. If you can, please also send me any articles about mongodb date indexing.

mongoose.js: finding data entries by day

Suppose this is your model:
var EventSchema = new Schema({
title: String,
startDate: Date,
endDate: Date
});
I would like to throw in a date (as simple as like '24-12-2012') and then retrieve every event that started or proceeded at that single day.
How do you do that?
Sure:
First read up on mongo query syntax for dates, here is a how-to for date ranges: http://cookbook.mongodb.org/patterns/date_range/
Then translate that mongo syntax into mongoose.
Event.where('startDate').lte(yourDate).exec(callback); //should do the trick
Now you just need to parse date strings to javascript dates. There are some cool libraries to do that, I believe that moment.js won't have a problem with that date string.
Oh, I forgot the last bit of magic: Put that query into a static method attached to your Event model, so from now on you can just call
Event.earlierThan(yourDate, callback); //Where your custom static is called 'earlierThan'.

Resources