Question

So I have a collections which stores the start and end times for an event and I would like a user to be able to query for events by specifying "filter" start and end times. The query should return any events that intersect with the filter times. I thought I was building the query correctly, but it's not returning the results I want.

Example data (simplified mongo document to get the idea, times are HHMMSS):

{ ..., "start" : "050520", "end" : "051309" } //Should match
{ ..., "start" : "051125", "end" : "051925" } //Should match
{ ..., "start" : "052049", "end" : "052420" } //Should match
{ ..., "start" : "050000", "end" : "050500" }
{ ..., "start" : "052100", "end" : "052721" }

The query I tried was (Forgive me if I missed a bracket here, that's not the issue):

find( { $or : [ 
            { start : { $gte : "050600", $lt : "052100" } }, 
            { end : { $lt : "052100", $gt : "050600" } } 
        ] } )

Which only returned one of the three results. Switching the order of the $or parts ( querying against the end times before the start times) gives me two results but not all three. I seem to remember reading that for compound queries mongo throws away results that don't match the first part, before applying the second part of the query, but I thought the $or operator would handle that. Any ideas? Is my query incorrect, is this a limitation of querying in mongo?

Était-ce utile?

La solution

Using MongoDB 2.4.5 I tried the above and got back in both cases the first 2 of your "Should match" results.

I don't believe the 3rd should be returned as it would require ("052049" >= "050600" && "052049" < "052000") or ("052420" < "052000" && "052420" > "050600") neither of which evaluate to true.

MongoDB shell version: 2.4.5
connecting to: test
> 
> db.mycol.save({ "start" : "050520", "end" : "051309" }) 
> db.mycol.save({ "start" : "051125", "end" : "051925" })
> db.mycol.save({ "start" : "052049", "end" : "052420" }) 
> db.mycol.save({ "start" : "050000", "end" : "050500" })
> db.mycol.save({ "start" : "052100", "end" : "052721" })
>
> db.mycol.find( 
... { $or : 
... [ { $and : [ { start : { $gte : "050600" } }, { start : { $lt : "052000" } } ] }, 
...   { $and : [ { end : { $lt : "052000" } }, { end : { $gt : "050600" } } ] } 
... ] 
...     } )
{ "_id" : ObjectId("520528522683a40682f12b5c"), "start" : "050520", "end" : "051309" }
{ "_id" : ObjectId("520528522683a40682f12b5d"), "start" : "051125", "end" : "051925" }
> 
> 
> db.mycol.find( 
... { $or : 
... [     { $and : [ { end : { $lt : "052000" } }, { end : { $gt : "050600" } } ] } , 
...   { $and : [ { start : { $gte : "050600" } }, { start : { $lt : "052000" } } ] }
... ] 
...     } )
{ "_id" : ObjectId("520528522683a40682f12b5c"), "start" : "050520", "end" : "051309" }
{ "_id" : ObjectId("520528522683a40682f12b5d"), "start" : "051125", "end" : "051925" }
> 

Autres conseils

Your query should work fine, but the third one shouldn't match as both start and end are out of the range.

However, you can write your query more clearly and succinctly as:

db.test.find({ $or: [
    { start: { $gte: "050600", $lt : "052000" }}, 
    { end: { $lt: "052000", $gt: "050600" }}
]});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top