hasyee
hasyee

Reputation: 130

mongo BadValue unknown operator: $or

The collection has one document:

{
    "_id" : ObjectId("54b513933aca242d9915a787"),
    "carriers" : [ 
        {
            "carrier" : ObjectId("54b54d223aca242d9915a788"),
            "carryingInterval" : {
                "from" : ISODate("2013-12-31T23:00:00.000Z"),
                "to" : null
            }
        }
    ]
}

I would like to make a criteria, that is looking for a certain carrier and range. The carryingInterval's from and to fields could be a Date object or null. The null value means +/- infinity.

My criteria is:

{
    carriers: {
        $elemMatch: {
            carrier: ObjectId('54b54d223aca242d9915a788'),
            carryingInterval: {
                $or: [
                    {
                        from: {$lt: Date()},
                        to: null
                    }
                ]
            }
        }
    }
}

This query cannot run with the following error message:

Can't canonicalize query: BadValue unknown operator: $or

Okey, I tried other criterias, like this:

{
    carriers: {
        $elemMatch: {
            carrier: ObjectId('54b54d223aca242d9915a788'),
            $or: [
                {
                    "carryingInterval.from": {$lt: Date()},
                    "carryingInterval.to": null
                }
            ]
        }
    }
}

It runs without any result however the from field is less then 'now' in the document. If I skip the from field from the criteria, i get it.

In this topic Will Berkeley says

$or should be on the top level

but in my second criteria the $or operator isn't on the top level, that is below the $elemMatch operator, and it works.

I don't understand this behavior. Please, explain me! Thx! :)

Upvotes: 3

Views: 16714

Answers (1)

JohnnyHK
JohnnyHK

Reputation: 311945

Calling Date() returns a string, not a Date; use new Date() to create a Date object of the current time.

So your query object needs to look like this instead:

{
    carriers: {
        $elemMatch: {
            carrier: ObjectId('54b54d223aca242d9915a788'),
            $or: [
                {
                    "carryingInterval.from": {$lt: new Date()},
                    "carryingInterval.to": null
                }
            ]
        }
    }
}

$or can be used within $elemMatch because it effectively creates a new top-level query object with respect to the elements of carriers.

Upvotes: 3

Related Questions