简体   繁体   中英

How to map _id parameter in aggregation

I defined a method to group data using the aggregation framework. The method accepts a list of fields on which you can group the data. I also created a class to map the result but the issue is that I don't know what type to give for the _id attribute. The _id can have different types depending on the number of fields used to group the data. I tried Object but it only work when grouping with zero or one field but not when using several fields.

public List<Metric> getMetric(List<String> fields) {
    MatchOperation match = match(where("status").in("WIN", "LOSS", "PUSH").and("year").gte(2015));
    GroupOperation group = group(fields.toArray(new String[0]))
            .count().as("count")
            .avg("odd").as("averageOdd")
            .sum("profit").as("profit")
            .push("$$ROOT").as("picks");
    Aggregation aggregation = Aggregation.newAggregation(
            match,
            group
    );
    // TODO: Handle _id
    AggregationResults<Metric> aggregationResults = mongoTemplate.aggregate(aggregation, "pick", Metric.class);
    return aggregationResults.getMappedResults();
}

public class Metric {

    //    private Map<String, Object> _id;
    //    private List<Object> _id;
    private Object _id;

    private Integer count;

    private Double profit;

    private Double averageOdd;

}

Using an empty list, the result (JSON representation of the List returned by the method) is:

[
    {
        "_id": null,
        "count": 1997,
        "profit": -0.07237707390649417,
        "averageOdd": 2.4241016559624624,
        "yield": -0.00003624290130520489
    }
]

Using one field, the partial result is:

[
    {
        "_id": 2016,
        "count": 751,
        "profit": -34.484,
        "averageOdd": 2.362993342210386,
        "yield": -0.04591744340878828
    }
]

Using several fields, the partial result is:

[
    {
        "_id": null,
        "count": 211,
        "profit": -18.961,
        "averageOdd": 3.1104597156398106,
        "yield": -0.08986255924170615
    }
]

I found a way to map an _id with several fields. In your mapped object you have to declare the fields that composed your _id .

_id: {
  sport: "MLB",
  year: 2016
}

In the mapped object you have to declare the fields sport and year . The not so convenient part is you have to keep the _id in your mapped object to handle the case for single field _id even though it's logic.

The relevant code from MongoTemplate :

class UnwrapAndReadDbObjectCallback<T> extends MongoTemplate.ReadDbObjectCallback<T> {
    public UnwrapAndReadDbObjectCallback(EntityReader<? super T, DBObject> this$0, Class<T> reader, String type) {
        super(reader, type, collectionName);
    }

    public T doWith(DBObject object) {
        Object idField = object.get("_id");
        if (!(idField instanceof DBObject)) {
            return super.doWith(object);
        } else {
            DBObject toMap = new BasicDBObject();
            DBObject nested = (DBObject)idField;
            toMap.putAll(nested);
            Iterator var5 = object.keySet().iterator();

            while(var5.hasNext()) {
                String key = (String)var5.next();
                if (!"_id".equals(key)) {
                    toMap.put(key, object.get(key));
                }
            }

            return super.doWith(toMap);
        }
    }
}

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