简体   繁体   中英

Morphia query in embedded list

my issue is to query a complex element.

@Entity("Activity")
public class Activity extends BaseEntity {
        private String name;
        private String description;
        private Date deadline;
        private Boolean completed;
        @Embedded
        private List<SubActivity> listSubActivity;
   .
   .
   .
}

where

@Entity("SubActivity")
public class SubActivity extends BaseEntity {
    private String name;
    private Date deadline;
    private Boolean completed;
.
.
.
}

I have to find all activities with sub-activities expired. I try with

Query<Activity> queryA = datastore.createQuery(Activity.class);
queryA.and(
   queryA.criteria("deadline").lessThan(today), // where today is a Date()
   queryA.criteria("completed").equal(false)
 );

but it does not work because retrieve also this activity

{
  "_id" : ObjectId("581352597dfd063decb0b357"),
  "className" : "com.etherweaver.collections.Activity",
  "name" : "Name",
  "description" : "description",
  "deadline" : ISODate("2016-11-02T23:00:00.000Z"),
  "completed" : true,
  "listSubActivity" : [{
      "name" : "sub activity 1",
      "deadline" : ISODate("2016-11-01T23:00:00.000Z"), 
      "completed" : true 
    }, {
      "name" : "sub activity 2",
      "deadline" : ISODate("2016-11-06T23:00:00.000Z"),
      "completed" : false
    }, {
      "name" : "sub activity 3",
      "deadline" : ISODate("2016-11-06T23:00:00.000Z"),
      "completed" : true
    }]
}

where sub activity 1 is expired but completed.

Is there is a method to query the list embedded with conditions verified line by line?

You can try something like below.

Query<SubActivity> query = datastore.createQuery(SubActivity.class)
        .filter("deadline < ", new Date())
        .filter("completed = ", true);

List<Activity> activities = datastore.find(Activity.class)
                                              .field("listSubActivity")
                                              .elemMatch(query)
                                              .asList();   

Update

To use hasThisElement, it only allows equals comparison not other conditional comparison.

So I'm not sure if this is going to work for you ,but sorry, I don't see any other way right now.

SubActivity filter = new SubActivity();
filter.setDeadline(new Date());
filter.setCompleted(true);

List<Activity> activities = datastore.find(Activity.class)
                                              .field("listSubActivity")
                                              .hasThisElement(filter)
                                              .asList();   

Update 2

Aggregation based approach - This approach will filter the rows based on the query.

import static org.mongodb.morphia.aggregation.Group.*;

Query<Activity> query = datastore.createQuery(Activity.class)
               .filter("listSubActivity.deadline < ", anyDate)
               .filter("listSubActivity.completed = ", true);

Iterator<Activity> activities = datastore.createAggregation(Activity.class).
               unwind("listSubActivity").
               match(query).
               group("_id", grouping("className", first("className")),
                       grouping("name", first("name")),
                       grouping("description", first("description")),
                       grouping("deadline", first("deadline")),
                       grouping("completed", first("completed")), grouping("listSubActivity", push("listSubActivity"))).aggregate(Activity.class);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM