0

Here is what I am working with:

{
    "_id": ObjectId("53b4402ae1382335c95952d3"),
    "created": ISODate("2014-07-02T10:23:54.245Z"),
    "modified": ISODate("2011-11-28T10:06:25.186Z"),
    "source": [{
        "instances": [{
            "analyst": "harry",
            "date": ISODate("2014-07-02T10:23:54.242Z"),
            "reference": "abb32"
        },
        {
            "analyst": "david",
            "date": ISODate("2014-07-02T10:33:02.296Z"),
            "reference": "can26"
        }],
        "name": "Apples"
    },
    {
        "instances": [{
            "analyst": "critsAPI",
            "date": ISODate("2011-11-28T10:06:25.156Z"),
            "reference": "z561c"
        }],
        "name": "Oranges"
    }],
    "releasability": [],
}

What I would like is a count of every document which has an "instances date " in a certain range (lets say a month) along with a certain name. I have used two queries with "elemMatch" and unfortunately I am not getting the results I expect. Here is what I have tried using elemMatch and instances.date:

    collection.find(
                    {
                    'source':
                      {
                        '$elemMatch' : {
                              'name':'Apples',
                              'instances.date' : {'$lte' :   ISODate("2014-07-30T00:00:00Z") ,    
                                                 '$gte' :  ISODate("2014-07-01T00:00:00Z")}
                       }
                       }
                       }
                        ).count()

Here is with a nested elemMatch :

    collection.find(
                    {
                    'source':
                      {
                        '$elemMatch' : {
                              'name':'Apples',
                              'instances': {
                                  '$elemMatch' : {
                                       'date' : {'$lte' :   ISODate("2014-07-30T00:00:00Z") ,    
                                                 '$gte' :  ISODate("2014-07-01T00:00:00Z")}
                       }
                       }
                       }
                       }
                       }
                        ).count()

Thanks in advance.

2 Answers2

1

My idea is to use dot notation to access the elements of an array combine with $and operator to query 'instances date' range.

collection.find({
'source' : {
    $elemMatch:{
        'name': 'Apples',
         $and:[ {'instances.date' : {$lte : ISODate("2014-07-30T00:00:00Z")}} , 
                {'instances.date' : {$gte : ISODate("2014-07-01T00:00:00Z")}}]
               }
           }})

Hope this help :)

tug
  • 71
  • 3
0

I'm guessing that your are getting a count() of 1 since the count() method returns the number of documents, not the number of array elements.

To get a result of 2 (based on the above document) you need to use the Aggregation Framework.

Please try something like the following:

    db.coll1.aggregate([ 
        {$unwind : "$source"},
        {$unwind : "$source.instances"},
        {$match: { 
            $and: [
            {"source.name" : "Apples"},
            {"source.instances.date" : {"$lte" : ISODate("2014-07-30T00:00:00Z")}},
            {"source.instances.date" : {"$gte" : ISODate("2014-07-01T00:00:00Z")}}
                  ]
        }},
        {$project: {
            name1: "$source.name",
            date1: "$source.instances.date"
        }},
            {$group : {_id: "$name1", name1: {$sum:1}}}
        ])
    
and I get the following in the shell { "result" : [ { "_id" : "Apples", "name1" : 2 } ], "ok" : 1 }

The $unwind breaks the array into separate docs, the $match does the selection, the $project defines the result fields (similar toSELECT clause in SQL), the $group sums the entries (similar to 'GROUP BY` in SQL)

These individual steps in the aggregation pipeline sequentially filters/transforms a result set of documents.

Hope that helps

DaveStSomeWhere
  • 2,475
  • 2
  • 22
  • 19
  • Why use `$and` here? The general premise is correct on the aggregation approach but you don't seem to understand the basics of the query operands. **And** conditions are basically "implicit". That is is a `101` for anyone seeking to impart knowledge. – Neil Lunn Feb 28 '15 at 14:38
  • Thank you very much Dave this was exactly what I was looking for. I did not realize that only the document would be included in the count. I did infact need a count of the different array elements. – user2012481 Mar 02 '15 at 18:33