Nodejs Cannot find document when using .find({}) method - node.js

I am trying to do a simple .find() using mongoose/nodejs with mongoDB. I have a document (with field "date": "09-20-2019") in my collection (show) but I cannot seem to find it programmatically.
I have tried using MongoDB compass (db viewer software) to perform a search for what I am looking for. I passed into the search box under my collection {date: "09-20-2019"} and I was able to find the document using their search functionality so I know it should be working. I have checked that the field "date" is coming across to back end node server as the correct format and value of "09-20-2019". I am using Node.js 10.15.1
--This is from my route.js file
router.get('/shows/:date', (req, res, next)=>{
//res.send('Retrieving the shows list');
console.log('back end date: ' + req.params.date);
Show.find({date: req.params.date}, function(err, result){
if (err)
{
res.json(err);
}
else {
console.log(result);
res.json(result);
}
})
});
--This is from my show.js (mongodb schema file)
const mongoose = require('mongoose');
const ShowSchema = mongoose.Schema({
name:{
type: String,
required: true
},
date:{
type: String,
required: true
},
venue:{
type: String,
required: true
},
createdDate:{
type: String,
required: true
}
});
const Show = module.exports = mongoose.model('Show', ShowSchema);
--This is from my service.ts file
getShow(date)
{
var headers = new Headers();
headers.append('Content-Type', 'application/json');
//date is in format MM/dd/yyyy (e.g. 09-20-2019)
return this.http.get<Show>('http://localhost:3000/api/shows/' + date);
}
--This is from my component
this.commentCardService.getShow(this._date).subscribe(data => {
console.log(data);
});
I am expecting the .find({}) operation to return with a single document from my mongoDB of the show with the date of '09-20-2019' which is the only document that is in that collection at the moment. More than one document will exist in the collection ultimately.

Please see also: https://stackoverflow.com/a/55386123/211827 — when querying dates, use actual dates. When querying ObjectIds use real ObjectIds. Etc. Because your strings are literally the worst possible date format for any form of lexicographical expectation. Specifically: not following the ISO date format form of least specific to most specific (year, month, day) will prevent any form of sorting, range querying, or essentially any of the "most useful" things you can use actual dates for when stored as strings, which is not an appropriate storage format for dates, generally.
"2019/09/21" = 11 bytes. The same date represented using the Julian calendar: 2458748, or a 32-bit integer (4 bytes), no time component. UNIX timestamp would be 64-bit, so 8 bytes, and you'd also have to throw away or ignore the time component within. Even the wrong right way is better than the wrong wrong way. ;)

Check-in you Database that there is date formate like '02/03/1995', it can be via saving, you are changing you formate if not then please share your one object of your schema.
This is working properly in my schema.
db.getCollection('users').find({dob:'02/03/1995'})

Check whether your date in db is in iso date or iso string format.
If it is an iso date than you will have to do new Date(09-20-2019).
If its an iso string then you also need to consider the timezone.
Try to find using a between query 09-20-2019 & 09-21-2019.
You should get the data.

Related

Is it possible to refer to "this" document in Mongoose?

I'm using Mongoose in Node.js, and I am wondering if it is possible to refer to the currently selected document using "this" or a similar mechanism. Here is the use case I'm looking for :
Mongoose Schema :
const mySchema = mongoose.Schema({
position: Number,
date: Number,
lastEventDate: Number
});
Let's say that, at some point in time, an event occurs.
For a document selected through its position, I want to update "lastEventDate" to the document's date.
Here is my dream code :
myModel.findOneAndUpdate(
{position: myPosition},
{$set: {
'lastEventDate': THISDOCUMENT.date
}}
);
Note : I'm using $set here because the actual code updates subdocuments...
Is there a built-in "THISDOCUMENT" reference such as the one I'm dreaming of, to do it all in a single query ?
Or do I have to first query the value before updating the document (two queries).
Couldn't find anything on the web, and I'm quite the newbie when it comes to using "this".
Thanks for any kind of help !
[EDIT :] Precisions about the objective :
I am in a situation where I only have the position "myPosition" to identify the correct document, and I want to set "lastEventDate" to the same value as "date" for that document.
My question is about efficiency : is it possible to perform the update in a single upload query ? Or do I have to first download the "date" value before uploading it back to the "lastEventDate" key ?
Gathering all the information provided, I will venture on a possible answer!
You could try something like:
Your schema JS file
const mySchema = mongoose.Schema({
position: Number,
date: Number,
lastEventDate: Number
});
mySchema.methods.doYourThing(){
this.lastEventDate=this.date; //it will set the lastEventDate
}
mongoose.model("myModel", MySchema, "mycollection")
Now, whenever you call doYourThing(), the action wanted will take place, you call it after you have a instance of the mode.
This is from my own code
const token = user.generateJwt(expirationDate); //send a token, it will be stored locally in the browser
it is inside a function that return an instance of user, and in the model User I have done a function called generateJwt like I have showed, and we have something like this:
return jwt.sign(
{
_id: this._id, //this is created automatically by Mongo
email: this.email,
name: this.name,
exp: parseInt(expiry.getTime() / 1000, 10), //Includes exp as UNIX time in seconds
level: this.level,
lastLogin: this.lastLogin,
failedLogin: this.failedLogin
},
process.env.JWT_SECRET
); // DO NOT KEEP YOUR SECRET IN THE CODE!
It returns all the information of the user!
Please, do not hesitate to add comments and feebacks, I am not sure it is what you want, but that is why I have understood your request.
Anothe option is using Virtuals, they also have access to this.

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.

Mongoose - Query a nested property of Schema.Type.Mixed as a specified data type (Date)

I have a schema setup in Mongoose with
var MySchema = new Schema({
data: {
type: Schema.Types.Mixed
}
});
My issue is that on this 'data' object i am storing a date value as a nested property, it all works fine until i try and do a find() query with Mongoose and search using the nested field. Because Mongoose doesn't know it is a Date it cant use the usual '$gte', '$lte' and similar operators im guessing because it sees that data as just a String.
One of my objects looks similar to this
{
title:"My object",
data:{
publishDate: "2016-07-12T05:00:48.985Z"
}
Is there anyway that i can explicitly tell Mongoose to expect the value to be a date so i can use '$gte' as an operator?
Model.find({
"data.publishDate":{
$gte:new Date()
}
})
Turns out i had to strictly type the value as a date before saving to the database. Otherwise the date operators '$gte', '$lte' etc would not work.
Solution is to do this
{
title:"My object",
data:{
publishDate: new Date("2016-07-12T05:00:48.985Z")
}
At this point i don't believe you can type the data dynamically when running a query.

Mongoose - get length of array in model

I have this Mongoose schema:
var postSchema = mongoose.Schema({
postId: {
type: Number,
unique: true
},
upvotes: [
{
type: Number,
unique: true
}
]
});
what the best query to use to get the length of the upvotes array? I don't believe I need to use aggregation because I only want to query for one model, just need the length of the upvotes array for a given model.
Really struggling to find this info online - everything I search for mentions the aggregation methodology which I don't believe I need.
Also, as a side note, the unique schema property of the upvotes array doesn't work, perhaps I am doing that wrong.
find results can only include content from the docs themselves1, while aggregate can project new values that are derived from the doc's content (like an array's length). That's why you need to use aggregate for this, even though you're getting just a single doc.
Post.aggregate([{$match: {postId: 5}}, {$project: {upvotes: {$size: '$upvotes'}}}])
1Single exception is the $meta projection operator to project a $text query result's score.
I'm not normally a fan of caching values, but it might be an option (and after finding this stackoverflow answer is what I'm going to do for my use case) to calculate the length of the field when the record is updated in the pre('validate') hook. For example:
var schema = new mongoose.Schema({
name: String,
upvoteCount: Number,
upvotes: [{}]
});
schema.pre('validate', function (next) {
this.upvoteCount = this.upvotes.length
next();
});
Just note that you need to do your updates the mongoose way by loading the object using find and then saving changes using object.save() - don't use findOneAndUpdate
postSchema.virtual('upvoteCount').get(function () {
return this.upvotes.length
});
let doc = await Post.findById('foobar123')
doc.upvoteCount // length of upvotes
My suggestion would be to pull the entire upvotes fields data and use .length property of returned array in node.js code
//logic only, not a functional code
post.find( filterexpression, {upvote: 1}, function(err, res){
console.log(res.upvotes.length);
});
EDIT:
Other way of doing would be stored Javascript. You can query the
upvote and count the same in mongodb side stored Javascript using
.length

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