shivam
shivam

Reputation: 491

Filter over Nested Map value's in Spring data mongo query-dsl

I am integrating the Spring-Data-mongo with query-dsl, so i need to Generate Q-files for query-dsl queries Here is my Order POJO:

public class Order {
    private List<Map<String,Object>> items;
}

My Q file of Order.java

public class QOrder extends EntityPathBase<Order> {

    private static final long serialVersionUID = -682690651L;

    public static final QOrder order = new QOrder("order");

    public final ListPath<java.util.Map<String, Object>, SimplePath<java.util.Map<String, Object>>> items = this.<java.util.Map<String, Object>, SimplePath<java.util.Map<String, Object>>>createList("items", java.util.Map.class, SimplePath.class, PathInits.DIRECT2);

    public QOrder(String variable) {
        super(Order.class, forVariable(variable));
    }

    public QOrder(Path<? extends Order> path) {
        super(path.getType(), path.getMetadata());
    }

    public QOrder(PathMetadata metadata) {
        super(Order.class, metadata);
    }
}

and sample json's of order is

{
    "items": [{
        "itemName": "phone",
        "quantity": <Integer-Number>
    }
    ]
}

Now i want to retrieve all the order's from mongo for which any Item exist with qunatity 1. Now i am generating my predicate like below. "QSensorData.sensorData.data.any().eq(Some-QueryDSL-Expression)".

I am unable to identify what need to pass in eq method for filtering nested map values.

Upvotes: 2

Views: 2584

Answers (1)

s7vr
s7vr

Reputation: 75924

Change Order class to include List attribute where Item contains itemName and quantity fields. Something like

public class Order {
    private List<Item> items;
}

public class Item {
    private String itemName;
    private Integer quantity;
}

Generate Q classes.

Use below query to return all items where there is atleast one item with quantity with 1.

BooleanExpression expression = QOrder.order.items.any().quantity.eq(1);
List<Order> results = repository.findAll(expression);

As noted in the comment to return all filtered items with value 1 you have to use aggregation query.

Something like

Static Imports

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.aggregation.ArrayOperators.Filter.filter;
import static org.springframework.data.mongodb.core.aggregation.ComparisonOperators.Eq.valueOf;

Aggregation Query

Aggregation aggregation = newAggregation(
           project().and(filter("items")
             .as("item")
             .by(valueOf(
                  "item.quantity")
                   .equalToValue(
                  1)))
          .as("items");
);

List<Order> results = mongoTemplate.aggregate(aggregation, Order.class, Order.class)

Upvotes: 4

Related Questions