google-code-export / morphia

Automatically exported from code.google.com/p/morphia
1 stars 0 forks source link

AND queries does not allow several filters on the same criteria #225

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
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 

Original issue reported on code.google.com by johan.se...@gmail.com on 9 Feb 2011 at 1:33

GoogleCodeExporter commented 9 years ago
This is a server limitation. http://jira.mongodb.org/browse/SERVER-1089

Original comment by scotthernandez on 9 Feb 2011 at 2:50

GoogleCodeExporter commented 9 years ago
Okey thanks, did not know that. How would I work around this when creating 
multiple filters for the same field?

Original comment by johan.se...@gmail.com on 11 Feb 2011 at 11:17

GoogleCodeExporter commented 9 years ago
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/g
oogle/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.

Original comment by scotthernandez on 11 Feb 2011 at 3:50

GoogleCodeExporter commented 9 years ago
Sorry that should be hasAllOf ($all) since you want and behavior.

Original comment by scotthernandez on 11 Feb 2011 at 3:51

GoogleCodeExporter commented 9 years ago
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.    

Original comment by johan.se...@gmail.com on 15 Feb 2011 at 9:02

GoogleCodeExporter commented 9 years ago
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() );
   }
}

Original comment by sdeit...@googlemail.com on 30 Dec 2011 at 3:49

GoogleCodeExporter commented 9 years ago
Any updates on this issue?

Original comment by tim.muri...@gmail.com on 13 Dec 2012 at 8:45

GoogleCodeExporter commented 9 years ago
Hi,

don't know if this issue is still of interest - but I faced the same problem 
when querying for the same field containing different strings in a 
"like"-manner with complete wildcard (i.e. field LIKE '%xyz%' and field like 
'%abc%' in SQL).
I finally solved it by making use of morphia's pattern-abillity for queries.
Actually the interesting part of code looks like this (sorry, some German 
variable names... ;):   

    Map<String, List> queries = new HashMap<>();
    for (Kriterium sb : kriterien) {
        if (sb.suchobjekt != null) {
            if (!queries.containsKey(sb.feld)) {
                queries.put(sb.feld, new ArrayList());
            }
            if (sb instanceof KriteriumWildcard && ((String) sb.suchobjekt).trim().length() > 0) {
                queries.get(sb.feld).add(Pattern.compile((String) sb.suchobjekt, Pattern.CASE_INSENSITIVE));
            } else {
                queries.get(sb.feld).add(sb.suchobjekt);
            }
        }
    }
    Query<EDIFACTNachrichtendatei> q = ds.createQuery(EDIFACTNachrichtendatei.class);
    for (Entry<String, List> entry : queries.entrySet()) {
        if (entry.getValue().size() > 0) {
            q.field(entry.getKey()).hasAllOf(entry.getValue());
        }
    }

As you can see, the most important trick is to combine the hasAllOf()-method 
with morphia's ability to understand regular expressions as values for this 
method's parameter objects. I don't know if this is really good practice but it 
works pretty well for me. I haven't tried so far to combine it with several 
other, different criteria (e.g. not being a like-pattern but a fixed object), 
so maybe there'll remain some drawbacks to still work around when using this 
strategy. 

Ben

Original comment by be.kl...@gmail.com on 28 May 2013 at 7:41