Reputation: 359
I doing a search system for a project in Meteor and need to put a field to search between two dates. However, the dates are within the array in MongoDB:
"relatorios" : [
{
"mes" : ISODate("2013-11-01T02:00:00Z"),
"revistas" : "2",
"brochuras" : "2",
"livros" : "0",
"folhetos" : "0",
"revisitas" : "0",
"estudos" : "0",
"horas" : "12"
},
{
"mes" : ISODate("2013-09-01T03:00:00Z"),
"revistas" : "0",
"brochuras" : "0",
"livros" : "0",
"folhetos" : "0",
"revisitas" : "0",
"estudos" : "0",
"horas" : "12"
}
]
I have tried to query filtering dates directly by mongo, but could not. I read on some forums about using MapReduce in Meteor. What is the best option? And if possible, how can I do?
Upvotes: 7
Views: 6882
Reputation: 293
let date = new Date();
let getFirstDay = new Date(date.getFullYear(), date.getMonth() + 1, 1);
let getLastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
let firstDay = getFirstDay.getFullYear() + '-' + ((''+getFirstDay.getMonth()).length<2 ? '0' : '') + getFirstDay.getMonth() + '-' + ((''+getFirstDay.getDate()).length<2 ? '0' : '') + getFirstDay.getDate()+"T00:00:00.000Z";
let lastDay = getLastDay.getFullYear() + '-' + ((''+getLastDay.getMonth()).length<2 ? '0' : '') + (getLastDay.getMonth()+1) + '-' + ((''+getLastDay.getDate()).length<2 ? '0' : '') + getLastDay.getDate()+"T00:00:00.000Z";
var pipeline = [
{
$match: { headofficeId: headofficeId }},
{ $match: {'createdDate': {$gt: new Date(firstDay), $lt: new Date(lastDay)}}},
{$group: {_id: "$branchId", total: {$sum: "$actualValue"}}},
{ $sort: { total: -1 }
}
];
var result = Commissions.aggregate(pipeline);
return result;
Upvotes: 0
Reputation: 312179
You can use $elemMatch
to find a single array relatorios
element that has a mes
value between two dates, and the $
positional projection operator to only include that matching element in the output.
In the shell:
start = new Date('2013-11-01T01:30:00Z');
end = new Date('2013-11-01T02:30:00Z');
db.test.find(
{relatorios: {$elemMatch: {mes: {$gt: start, $lt: end}}}},
{'relatorios.$': 1})
If you don't use $elemMatch
then it could match $gt
against one element and $lt
against another.
Or if you need to get all relatorios
elements in the date range (instead of just the first), you can use aggregate
:
db.test.aggregate([
// Get all docs with at least one element in the date range
{$match: {relatorios: {$elemMatch: {mes: {$gt: start, $lt: end}}}}},
// Duplicate each doc, once per relatorios element.
{$unwind: '$relatorios'},
// Filter those to just the ones in the date range.
{$match: {'relatorios.mes': {$gt: start, $lt: end}}}
])
Upvotes: 0
Reputation: 75985
You can use dot notation e.g for two dates between a and b
var start = new Date(450000);
var end = new Date(5450000000000);
CollectionName.find({ 'relatorios.mes' : { $gte : start, $lt: end });
So this would get all documents which have an array which match this field. Remember mongodb extracts documents, so if you have just one array which matches it will give you the whole document.
Upvotes: 12