1

I have nested array database records styled as such:

{
"_id" : "A",
"foo" : [ 
    {
        "_id" : "a",
        "date" : ISODate("2017-07-13T23:27:13.522Z")
    }, 
    {
        "_id" : "b",
        "date" : ISODate("2017-08-04T22:36:36.381Z")
    }, 
    {
        "_id" : "c",
        "date" : ISODate("2017-08-23T23:59:40.202Z")
    }
]
},
{
"_id" : "B",
"foo" : [ 
    {
        "_id" : "d",
        "date" : ISODate("2017-07-17T23:27:13.522Z")
    }, 
    {
        "_id" : "e",
        "date" : ISODate("2017-01-06T22:36:36.381Z")
    }, 
    {
        "_id" : "f",
        "date" : ISODate("2017-09-14T23:59:40.202Z")
    }
]
},
{
"_id" : "C",
"foo" : [ 
    {
        "_id" : "g",
        "date" : ISODate("2017-11-17T23:27:13.522Z")
    }, 
    {
        "_id" : "h",
        "date" : ISODate("2017-06-06T22:36:36.381Z")
    }, 
    {
        "_id" : "i",
        "date" : ISODate("2017-10-14T23:59:40.202Z")
    }
]
}

When I run the query:

db.bar.find(
    {
        $and: [
                  {"foo.date": {$lte: new Date(2017,8,1)}}, 
                  {"foo.date": {$gte: new Date(2017,7,1)}}
       ]
    },
    {
       "_id":1
    }
)

I'm returned

{ 
    _id: "A"
},
{ 
    _id: "B"
},
{ 
    _id: "C"
}

Logically I'm asking for only the records where at least one date is between Aug-1 and Sept-1 (Record A), but am getting all records.

I'm thinking it might be referencing different dates on the subdocuments i.e. where foo.1.date > Aug-1 and foo.0.date < Sept-1.

Has anyone else had issue and found a resolution to this?

3 Answers 3

1

Your filters are evaluated separately against each subdocument in your array and that's why you're getting all results. For instance for C

  • element with _id g is gte 1st of August
  • element with _id h is lte 1st of September

You should use $elemMatch to find date in specified range

    db.bar.find(
    { "foo": 
        { 
            "$elemMatch": 
                { "date": 
                    { 
                        "$gte": new Date(2017,7,1), 
                        "$lte": new Date(2017,8,1) 
                    } 
                } 
            } 
    })

Only A will be returned for this query.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I was suspecting that was the issue. $elemMatch was the solution.
0

The way you are doing doensn't work as you want for array.

You have to unpack the array and after you compare the values.

 db.bar.aggregate(
// Unpack the assignments array
{ $unwind : "$foo" },

// Find the assignments ending after given date
{ $match : {
    "foo.date": { $gte: new Date(2017,7,1),$lt: new Date(2017,8,1)  }
}}
)

1 Comment

Thanks, this was a valid response, but for my use case required using "find".
0

This should also work fine

 db.bar.find({"foo.date": { $gte: new Date(2017,7,1),$lt: new Date(2017,8,1)  }})

1 Comment

yes, that's equivalent to the query I was running in my initial post. Make a collection with the sample data I provided and you'll see that it returns [A, B, C]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.