New issue 225 by johan.se...@gmail.com: AND queries does not allow several
filters on the same criteria
http://code.google.com/p/morphia/issues/detail?id=225
For instance,
query.and(
query.criteria("name").contains("Jack"),
query.criteria("name").startsWithIgnoreCase("Hip")
);
One would expect that the query would match names that start with Hip and
also contains Jack.
The produced query however looks as follows:
{ "name" : { "$regex" : "^Hip" , "$options" : "i"}}
I.e. the first criteria is missing.
What version are you using? (Morphia/Driver/MongoDB)
morphia 1.0 snapshot / mongodb 1.6.5 / driver 2.4
This is a server limitation. http://jira.mongodb.org/browse/SERVER-1089
Okey thanks, did not know that. How would I work around this when creating
multiple filters for the same field?
In this specific case you can work arround it by using hasAnyOf ($in) and
specifying the values in a List.
http://code.google.com/p/morphia/wiki/Query#Methods
http://code.google.com/p/morphia/source/browse/trunk/morphia/src/main/java/com/google/code/morphia/query/FieldEndImpl.java?r=1650#71
In general there aren't always ways to use $in/nin/all to work around this
limitation.
Sorry that should be hasAllOf ($all) since you want and behavior.
Again thanks for your answer. I was hoping to be able to use multiple
filters with startsWith, ignorecase etc.. so the hasAllOf doesn't really
suffice.
Since 2.0, there is an $and operator, so it would be great if this would be
supported in Morphia.
Complete test case (tested with Morphia 1.00-SNAPSHOT, Java driver 2.7.2,
MongoDB 2.0.1):
public class TestCase
{
@Entity( "documents" )
private static class Document
{
@Id
public ObjectId id;
public List< String > keywords = new ArrayList< String >();
}
public static void main( String[] args ) throws UnknownHostException,
MongoException
{
Morphia morphia = new Morphia();
morphia.mapPackageFromClass( Document.class );
Mongo mongo = new Mongo();
Datastore ds = morphia.createDatastore( mongo, "test" );
ds.delete( ds.find( Document.class ) );
Document doc1 = new Document();
doc1.keywords.add( "foobar" );
doc1.keywords.add( "operator-test" );
ds.save( doc1 );
Document doc2 = new Document();
doc2.keywords.add( "something" );
doc2.keywords.add( "tested" );
ds.save( doc2 );
Query< Document > query = ds.find( Document.class );
query.and( query.criteria( "keywords" ).contains( "foo" ),
query.criteria( "keywords" ).contains( "test" ) );
// should print 1, but prints 2
System.out.println( query.countAll() );
DBCollection documents = mongo.getDB( "test"
).getCollection( "documents" );
BasicDBList criteria = new BasicDBList();
criteria.add( new BasicDBObject( "keywords", new
BasicDBObject( "$regex", "foo" ) ) );
criteria.add( new BasicDBObject( "keywords", new
BasicDBObject( "$regex", "test" ) ) );
// this prints 1 as expected
System.out.println( documents.find( new BasicDBObject( "$and",
criteria ) ).count() );
}
}