Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

mongodb - Mongoose Aggregation does not Filter by Input Date

I'm trying to build a aggregation query but when I use $match with dates, it doesn't work as I expect. If I use other fields instead of any Date field, it works as expected. The code examples I'm using is below:

const res = await Reservation.aggregate([{ $match: { createdAt: { $lte: req.endDate } } }]).exec();

const res = await Reservation.find({ createdAt: { $lte: req.endDate } }).exec();

The first line doesn't work but the second one works perfectly. What is the difference between .find() and .aggregate(). Thanks for your help!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Mongoose has "schemas" for which it does this magic thing called "autocasting" for you. The typical case the designer(s) have in mind here is that all input from "web" interations like GET and POST is basically contained in a "string".

Whether or not there is some helper that that makes paramters into objects with keys and values, all those "values" are still "strings", or possibly made directly numeric by the same "helpers" where appropriate. This is common web framework design.

So when you issue a .find(), this function is completely incapable of altering the returned content other than by omission for fields/properties, so hence the "schema" is applied.

The .aggregate() method is entirely different. It's entire existence is to modify content contained in documents and collections. The consequence of this is that it is "impossible" for a schema to apply.

Hence, the "autocasting" present in methods like .find() does not happen, and you are required to cast elements ( such as the "string" your "date" is being sent in as ) to the correct types yourself:

Reservation.aggregate([
   { "$match": { "createdAt": { "$lte": new Date(req.endDate) } } }
])

Even if all you are doing is a $match and that you have not "modified" the schema in any way, mongoose does not "presume" this and does not attempt to cast to the matching field in the schema.

The logic here is that a $match stage or anything similar that could be bound to a "type", could occur anywhere within the pipeline. As such there is no guarantee that the documents being acted on by a pipeline stage bear any resemblance to the original collection schema.

Arguably it "could" possibly consider the fact that this is the first pipeline stage where nothing could possibly have changed and do a similar inspection. But that is not how the current code base worked.

So in short, when using the aggregation pipeline, all objects that need to be specifically cast to a type ( Date, ObjectId, etc ) need to be "manually" cast in your code, rather than assuming mongoose is going to do it for you like in other methods.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...