Amit Pal
Amit Pal

Reputation: 11052

How to perform aggregation in morphia?

I have a List of an object and I need to perform a query in Morphia to get the unique result from another embedding List of String in given object.

Object Class:

@Entity
public class Fruits {
  @NotNull private Long id;
  @NotNull private List<String> categories;
}

Data in Json Format:

Fruits:

 {[
  "id": 1234566,
  "categories": ["A", "B", "C", "D"]
 ],
 [
  "id": 32434,
  "categories": ["A", "C", "E", "F"]
 ],
 [
  "id": 32434,
  "categories": ["A", "L", "M", "N"]
 ] 
}

The result of aggregation supposed to be:

[A,C,B,D,E,F,L,M,N]

The output is in sorted form. How can I achieve this in morphia? I tried to search on official documentation but couldn't find the hint.

Any help or hint would be appreciable. Thanks

EDIT-1

List<Fruits> fruitList = fruitControllerDao.search(fruitList);

List<Category> categories = new ArrayList<>();
datastore.createAggregation(Fruits.class)
         .unwind("categories")
         .group(Group.id(Group.grouping("categories")))
         .sort(Sort.ascending("_id.categories"))
         .project(Projection.projection("_id").suppress(), 
          Projection.projection("categories", "_id.categories"))

         .aggregate(Category.class).forEachRemaining(categories::add);

and I have created

class Category {
   private String category;
}

Data in fruitList is unusable and I need to apply aggregation on the fruitList (Checkout the JSON Format) itself.

Upvotes: 1

Views: 3019

Answers (1)

s7vr
s7vr

Reputation: 75934

You can use below code to get unique & sort categories using aggregation pipeline.

Prepare Query Filter:

Query<Fruits> query = datastore.createQuery(Fruits.class);
Iterator<Fruits> fruitIterator = fruitList .iterator();
CriteriaContainer orQuery = query.or();
while(fruitIterator.hasNext()) {
      Fruits fruit = fruitIterator.next();
      orQuery.add(query.and(query.criteria("id").equal(fruit.getId()), query.criteria("categories").equal(fruit.getCategories())));
 }

The below query $matches on query filter and $unwinds the categories followed by $group to remove the duplicates and sorting. The last step is to read the value from grouping stage and $project into category field.

 List<Category> categories = new ArrayList<>();
  datastore.createAggregation(Fruits.class)
        .match(query)
        .unwind("categories")
        .group(Group.id(Group.grouping("categories")))
        .sort(Sort.ascending("_id.categories"))
        .project(Projection.projection("_id").suppress(), Projection.projection("category", "_id.categories"))
        .aggregate(Category.class).forEachRemaining(categories::add);


class Category {
    private String category;
}

Update:

Mongo Shell Query

   [{ "$match" : { "$or" : [ { "$and" : [ { "_id" : 1234566} , { "categories" : [ "A" , "B" , "C" , "D"]}]} , { "$and" : [ { "_id" : 32434} , { "categories" : [ "A" , "C" , "E" , "F"]}]} , { "$and" : [ { "_id" : 32434} , { "categories" : [ "A" , "L" , "M" , "N"]}]}]}}, { "$unwind" : "$categories"}, { "$group" : { "_id" : { "categories" : "$categories"}}}, { "$sort" : { "_id.categories" : 1}}, { "$project" : { "_id" : 0 , "category" : "$_id.categories"}}]

Upvotes: 2

Related Questions