med.tu
med.tu

Reputation: 135

Use $cond within $match in mongoDB aggregation

i've tried to use $cond within $match in one of the stages of an aggregation as shown below :

{ "$match" : { 
  "field1" : { 
                "$cond" : {
                   "if" : { "$eq" : [ "$id" , 1206]},
                   "then" : 0,
                   "else" : 1545001200
                }
             }, 
  "field2" : value2 }}

But i got this error :

Error:
Assert: command failed: {
"ok" : 0,
"errmsg" : "unknown operator: $cond",
"code" : 2,
"codeName" : "BadValue"
} : aggregate failed

The mongodb version is 3.4.4. Any idea about this issue?

Upvotes: 7

Views: 11518

Answers (3)

Victor Schröder
Victor Schröder

Reputation: 7747

Unless important details were left out of the question, I think you are complicating something simple. Filtering during a $match aggregation step is the natural expected thing it should do.

For this particular example, there are only two simple scenarios to match a document. There is no need to use any other operators, just define the two different mutually exclusive queries and put them in an $or logical operator:

{'$match': {'$or': [
  {'id': 1206, 'field1': 0},
  {'id': {'$ne': 1206}, 'field1': 1545001200},
]}}

Upvotes: 0

OliviaLynn
OliviaLynn

Reputation: 143

For those coming across this later on down the road:

This won't work for 3.4.4. But in MongoDB 3.6 they introduced the $expr operator that lets you use $cond and other operations within a $match query.

https://docs.mongodb.com/manual/reference/operator/aggregation/match/

For an example see iamfrank's answer.

Also as mentioned in the comments you could do this later down the pipeline. But ideally you'll want to filter out results as early on in the pipeline using $match in order to improve processing times.

Upvotes: 1

Raphael
Raphael

Reputation: 562

You just have to reword the logic a little bit.

{ $match: { $expr: {
    $or: [
        { $and: [
            { $eq: [ "$id", 1206 ] },
            { $eq: [ "$field1", 0 ] }
        ]},
        { $and: [
            { $ne: [ "$id", 1206 ] },
            { $eq: [ "$field1", 1545001200 ] }
        ]},
    ],
}}}

Logically, the two statements are equivalent:

  • Match the document by checking field1 == 0 if id == 1206, otherwise match the document by checking field1 == 1545001200
  • Match the document if either (id == 1206 and field1 == 0) or (id != 1206 and field1 == 1545001200).

Upvotes: 7

Related Questions