Narinder Kumar
Narinder Kumar

Reputation: 481

How to combine multiple criteria in OR query dynamically in Play Morphia

I am trying to use a kind of builder pattern to build an OR query using multiple criteria depending upon the scenario. An example is

    public class Stylist extends Model {

      public String firstName;

      public String lastName;

      public String status;

      ...

      }

I would like to search Stylist collection if the first name or last name matches a given string and also status matches another string. I am writing the query as follows:

      MorphiaQuery query = Stylist.q();
      if (some condition) {
      query.or(query.criteria("status").equal("PendingApproval"), query.criteria("status").equal(EntityStatus.ACTIVE));    
      }

      if (some other condition as well) {
      query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
      }

When both the conditions are met, I see that query contains only the criteria related to firstName and lastName i.e. different OR criteria are not added/appended but overwritten. It's quite different from filter criteria where all the different filter conditions are appended and you can easily build queries containing multiple AND conditions.

I can solve the problem by putting my conditions differently and building my queries differently but doesn't seem to be an elegant way. Am I doing something wrong ?

I am using Play! Framework 1.2.4 and Play Morphia module version 1.2.5a

Update

To put it more clearly, I would like to AND multiple OR queries. Concretely, in the above mentioned scenario, I would like to

I would like to search for Stylists where :

firstName or lastName contains supplied name AND

status equals ACTIVE or PENDING_APPROVAL.

I have been able to construct the query directly on Mongo shell through :

db.stylists.find({$and: [{$or : [{status: "PENDING_APPROVAL"}, {status : "ACTIVE"}]},{$or : [{firstName : { "$regex" : "test" , "$options" : "i"}}, {lastName : { "$regex" : "test" , "$options" : "i"}}]}] }).pretty();

But have not able to achieve the same through Query API methods. Here is my attempt :

    Query<Stylist> query = MorphiaPlugin.ds().find(Stylist.class);

    CriteriaContainer or3 = query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));

    CriteriaContainer or4 = query.or(query.criteria("status").equal("PENDING_APPROVAL"), query.criteria("status").equal("ACTIVE"));

    query.and(or3, or4);

query.toString() results in following output : { "$or" : [ { "status" : "PENDING_APPROVAL"} , { "status" : "ACTIVE"}]}

Not sure, where am I missing ?

Upvotes: 0

Views: 2742

Answers (1)

Gelin Luo
Gelin Luo

Reputation: 14373

I guess there could be 2 ways to handle your case:

first, use List<Criteria>

MorphiaQuery query = Stylist.q();
List<Criteria> l = new ArrayList<Criteria>()

if (some condition) {
  l.add(query.criteria("status").equals("PendingApproval");
  l.add(query.criteria("status").equal(EntityStatus.ACTIVE));
}

if (some other conditional as well) {
  l.add(query.criteria("firstName").containsIgnoreCase(name));
  l.add(query.criteria("lastName").containsIgnoreCase(name));
}

query.or(l.toArray());

Second, use CritieriaContainer

MorphiaQuery query = Stylist.q();
CriteriaContainer cc = null;

if (some condition) {
  cc = query.or(query.criteria("status").equal("PendingApproval"), query.criteria("status").equal(EntityStatus.ACTIVE));
}

if (some other condition) {
  if (null != cc) query.or(cc, query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
  else query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
}

Upvotes: 0

Related Questions