7

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?

Murilo Venturoso
  • 359
  • 5
  • 16

3 Answers3

12

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.

Tarang
  • 75,157
  • 39
  • 215
  • 276
  • 1
    I did it this way, but mongo returned all elements of the array and not just what were the dates. There's no way he returns only the elements that match the query? Or how do I get to the Meteor only the elements that match? – Murilo Venturoso Jun 30 '14 at 13:24
  • I got it! I'm removing the elements that do not match the date in direct Meteor. Thank you! – Murilo Venturoso Jun 30 '14 at 14:05
  • i think it should be `CollectionName.find({ 'relatorios.mes' : { $gte : start, $lt: end }});` note the extra `}` – Andy B Aug 07 '19 at 20:08
0

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}}}
])
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
  • From what I know, Meteor does not support aggregate – Murilo Venturoso Jul 01 '14 at 16:13
  • @MuriloVenturoso There do appear to be workarounds for that: http://stackoverflow.com/a/18884223/1259510 – JohnnyHK Jul 01 '14 at 16:16
  • I am running code that you passed, but the Meteor returns the following error: Object [object Object] has no method 'aggregate' – Murilo Venturoso Jul 01 '14 at 16:33
  • If you added something like the meteorhacks:aggregate package (https://atmospherejs.com/meteorhacks/aggregate) then you can only do aggregations server side. Trying to do it client side or trying to do it without the aggregation package would give you an error like that. – Helo Mar 14 '16 at 17:08
0
    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;
Thusila Bandara
  • 285
  • 4
  • 22