How to write Java ProjectionOperation computation

Following is the code screen shot

Screen Shot 2020-03-17 at 6.33.51 PM

values of variables are

From debugging values are

Constants.NESTED_CATEGORY_ITEMIDS is 

{ $arrayElemAt: [{ $arrayElemAt: [{ $arrayElemAt: ['$categories.subCategories.subCategories.itemIds',2]},2]},0]}

Constants.NESTED_CATEGORY_LEVEL is 

categories.2.subCategories.2.subCategories.0.itemIds

Constants.NESTED_CATEGORY_VALUE is

categories.subCategories.subCategories.subCategoryName

menuId  is 5e597a2be08a070bab329ef3

categoryName is Fish Taco

From debugging aggregation value is

{ "aggregate" : "__collection__", "pipeline" : [{ "$match" : { "_id" : { "$oid" : "5e597a2be08a070bab329ef3" }, "categories.subCategories.subCategories.subCategoryName" : "Fish Taco" } }, { "$project" : { "subCategories.subCategories.itemIds',2]},2]},0]}}]}" : "$categories.subCategories.subCategories.itemIds',2]},2]},0]}}]}" } }] } 

after running mongotemplate aggregate with following payload

Screen Shot 2020-03-17 at 6.35.02 PM
I am getting following error

Screen Shot 2020-03-17 at 6.36.09 PM

Please help me in writing projections to get the Constants.NESTED_CATEGORY_ITEMIDS

Hi @SatishReddy, welcome!

Assuming that you have the following document structure:

{
  "menuId": "5e597a2be08a070bab329ef3",
  "categories": [
    {
      "categoryName": "Dinner",
      "level": 2,
      "subCategories": [
        {
          "level": 0, 
         "subCategoryName": "Fish Taco",
          "items": [ { "itemId": "bar" }, { "itemId": "foo" } ]
        }
      ]
    }
  ]
}

Using your example $arrayElemAt, here’s how you can use com.mongodb.client.model.Projections.computed():

AggregateIterable<Document> iterable = collection.aggregate(Arrays.asList(
    Aggregates.match(Filters.eq("menuId", "5e597a2be08a070bab329ef3")),   
    Aggregates.project(
        Projections.fields(
            Projections.computed(
                "itemIds",
                 new Document("$arrayElemAt", 
                      Arrays.asList(new Document("$arrayElemAt", 
                          Arrays.asList(new Document("$arrayElemAt",
                              Arrays.asList("$categories.subCategories.items.itemId", 0)), 0)), 1))
            )
        )
    )
));

Please see also MongoDB Java driver: Use Aggregation Expressions.

If you’re using spring-data MongoTemplate, make sure that the version supports the driver’s Projections.computed(). The error that you posted looks like related to spring-data Mapping and MappingMongoConverter, make sure that it supports Projections.computed() as well.

Regards,
Wan.

1 Like

Thanks @wan. Using Projections.computed() returns Bson. Can you please let me know how to convert Bson to ProjectOperation or how to do using ProjectionOperation.

Hi @SatishReddy,

Perhaps you are trying to mix Aggregation between MongoDB Java driver and spring-data-mongodb Projection Operation. The above example is for MongoDB Java driver, if you’re using spring-data-mongodb you could try to use ArrayOperators.ArrayElemAt aggregation operator instead.

If you have further questions about the use of spring-data-mongodb, I’d suggest posting a question on StackOverflow: spring-data-mongodb to reach wider audience with the expertise.

Regards,
Wan

1 Like

What does the output (the result document fields and values) from the projection look like?

@Prasad_Saya

Using following document

{
  "menuId": "5e597a2be08a070bab329ef3",
  "categories": [
    {
      "categoryName": "Dinner",
      "level": 2,
      "subCategories": [
        {
          "level": 0, 
         "subCategoryName": "Fish Taco",
          "items": [ { "itemId": "bar" }, { "itemId": "foo" } ]
        }
      ]
    }
  ]
}

how to get following result using ProjectionOperation

{"items": [ { "itemId": "bar" }, { "itemId": "foo" } ]}

This is the MongoDB Spring Data (v2.2.6) code using MongoTemplate, and returns the expected output document:

MongoOperations mongoOps = new MongoTemplate(MongoClients.create(), "test");

Aggregation agg = newAggregation(
                      project()
                          .and(arrayOf("categories.subCategories.items").elementAt(0))
                          .as("items")
                          .andExclude("_id")
);

AggregationResults<Document> results = mongoOps.aggregate(agg, "collection", Document.class);
results.forEach(doc -> System.out.println(doc.toJson()));
1 Like