Simple code for getting documents that have a creationDate
between two values in mongodb.
If the user provides only one of the values the code should still work and get the documents that have either a creationDate
less than or bigger than the given value.
I'm mainly looking for more readability and simplicity.
interface mongoDateFilter {
$gte?: Date;
$lte?: Date;
}
export const getReportsForContent = async (
contentId: ObjectId,
beginDate: Date | undefined,
endDate: Date | undefined,
): Promise<Report[]> => {
const reportsCollection = await getCollection('reports');
const creationDateMongoFilter: mongoDateFilter = {};
if (beginDate) {
creationDateMongoFilter['$gte'] = beginDate;
}
if (endDate) {
creationDateMongoFilter['$lte'] = endDate;
}
let reportsForContent: Report[] = [];
if (beginDate || endDate) {
reportsForContent = await reportsCollection.find({ contentId, creationDate: creationDateMongoFilter }).toArray();
} else {
reportsForContent = await reportsCollection.find({ contentId }).toArray();
}
return reportsForContent;
};
```
1 Answer 1
Prefer dot notation over bracket notation when syntax permits it - it's a bit easier to read and write. ESLint rule: dot-notation
.
Construct objects all in one go rather than mutating them afterwards, if you can - it's easier to write (especially in TypeScript, since you don't have to denote the type ahead of time) and can be easier to understand at a glance when unnecessary mutation is avoided.
Don't assign expressions that won't be used - with
let reportsForContent: Report[] = [];
regardless of the situation, reportsForContent
will be reassigned to something else afterwards, so you can leave off the = []
part.
Or, even better:
Return the value retrieved instead of reassigning a variable and then returning the variable. This:
if (beginDate || endDate) {
reportsForContent = await reportsCollection.find({ contentId, creationDate: creationDateMongoFilter }).toArray();
} else {
reportsForContent = await reportsCollection.find({ contentId }).toArray();
}
can be
if (beginDate || endDate) {
return reportsCollection.find({ contentId, creationDate: creationDateMongoFilter }).toArray();
} else {
return reportsCollection.find({ contentId }).toArray();
}
Or, even better, handle the case where no date is set at the very beginning, and only construct the creationDateMongoFilter
later, if it's needed.
In all:
export const getReportsForContent = async (
contentId: ObjectId,
beginDate: Date | undefined,
endDate: Date | undefined,
): Promise<Report[]> => {
const reportsCollection = await getCollection('reports');
if (!beginDate && !endDate) {
return reportsCollection.find({ contentId }).toArray();
}
const creationDateMongoFilter = {
(...beginDate && { $gte: beginDate }),
(...endDate && { $lte: endDate }),
};
return reportsCollection.find({ contentId, creationDate: creationDateMongoFilter }).toArray();
};
No need for the mongoDateFilter
interface anymore.
-
\$\begingroup\$ Sending
undefined
to one of$gte
or$lte
while the other one is a defined and a date, will not result in the same behavior as supplying only one of$gte
or$lte
that's why I had those if statements and conditionally filled thecreationDateMongoFilter
object \$\endgroup\$ATheCoder– ATheCoder2020年12月09日 22:53:31 +00:00Commented Dec 9, 2020 at 22:53 -
1\$\begingroup\$ Oh, that's unfortunate, that's a surprisingly strict interpretation Mongo has. Tweak is simple enough, you can conditionally add properties to the object during its definition, see stackoverflow.com/q/11704267 \$\endgroup\$CertainPerformance– CertainPerformance2020年12月10日 00:27:45 +00:00Commented Dec 10, 2020 at 0:27
Explore related questions
See similar questions with these tags.