org.springframework.data.mongodb.InvalidMongoDbApiUsageException:
Due to limitations of the org.bson.Document, you can't add a second '$or'
expression specified as '$or: [Document{{active=false}},
Document{{active=null}}]'; Criteria already contains '$or:
[Document{{payerId=Document{{$in=[64aeae270d0313320626dc55]}}}},
Document{{payerLoginId=Document{{$in=[64aeae270d0313320626dc55]}}}}]'
For the famous above issue there is a well-known workaround, instead of:
criteria.orOperator(Criteria.where(field).is(value),
Criteria.where(field).is(anotherValue));
criteria.orOperator(Criteria.where(field2).is(value2),
Criteria.where(field2).is(anotherValue2));
To chain the multiple $or
within an $and
:
criteria.andOperator(
new Criteria().orOperator(Criteria.where(field).is(value),
Criteria.where(field).is(anotherValue)),
new Criteria().orOperator(Criteria.where(field2).is(value2),
Criteria.where(field2).is(anotherValue2)));
Though my question is what limitation are we workarounding here? The mongodb itself can work well with:
{$or:[{field:"value"}, {field:"anotherValue"}],
$or:[{field2:"value2"}, {field2:"anotherValue2"}]}
UPDATE:
Thanks aneroid for pointing this out: multiple $or
are not accepted by mongodb query syntax. Now my question would be towards MongoDB's team. Why $and
is implicitly assumed when chaining multiple equality conditions, but not when chaining such $or
ones?
The reason a workaround is necessary is you are not building a BSON query directly. The example code there builds a Java object, which will then be converted to BSON when submitted to the database server.
When you build a query like
criteria.orOperator(Criteria.where(field).is(value),
Criteria.where(field).is(anotherValue));
criteria.orOperator(Criteria.where(field2).is(value2),
Criteria.where(field2).is(anotherValue2));
that is essentially the same as the query:
{
"$or":[{"field":value},{"field":anotherValue}],
"$or":[{"field2":value2},{"field2":anotherValue2}]
}
Note that this is not a valid Java object as it has the same field name, $or
twice.
The BSON spec does not explicitly prohibit duplicate field names in a document, but Java does:
Object properties are an instance of java.util.Dictionary, which specifies:
In any one Dictionary object, every key is associated with at most one value.
So it is not possible to build a Java object with 2 properties associated with different values, but both with the same name.
The workaround of wrapping the pair of $or
clauses in an $and
clause effectively moves them to an array where each $or
is in a separate object:
{"$and":[
{"$or":[{"field":value},{"field":anotherValue}]},
{"$or":[{"field2":value2},{"field2":anotherValue2}]}
]}
This avoids the duplicate property name in a single object, while allowing the intended logic to be applied.