java - 聚合框架 - 组操作抛出 NumberFormatException

标签 java mongodb spring-data-mongodb

我正在使用Spring-Data MongoDB聚合框架

这是一个代码示例:

Aggregation agg = Aggregation.newAggregation(
    match(Criteria.where("type").is("PROMO")),
    group("locale")//.count().as("counts")
);


AggregationResults<Message> results = mongoTemplate.aggregate(agg, "message", Message.class);
return results.getMappedResults();

抛出:

org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type java.math.BigDecimal for value 'CL'; nested exception is java.lang.NumberFormatException

CL 是区域设置字段上的值,但我不明白为什么会抛出该异常。 我使用 documentation 中的类似示例.

已解决:

Aggregation agg = Aggregation.newAggregation(
           match(Criteria.where("type").is("PROMO")),
           group("created", "text").addToSet("locale").as("countries").addToSet("device.deviceType").as("platforms").count().as("count")
    );

我在 mongo 控制台上尝试了一个简单的示例。之后,将操作映射到构建器。 我不明白为什么以前不工作。如果有人能解决这个问题那就太好了。

模型“消息”:

{ "_id" : "90.0", "device" : { "_id" : "5faf92fd-37f2-4d42-a01a-dd1abce0c1af", "deviceType" : "iPhone", "countryId" : "AR" }, "text" : "Text", "created" : ISODate("2014-01-03T15:56:27.096Z"), "status" : "SENT", "type" : "PROMO" }

最佳答案

我的简单答案是避免直接使用 MongoDB Spring Data 类进行聚合,并使用标准 MongoDB Java 对象,例如DBObject/AggregationOutput。原因是我花了几个小时试图在 MongoDB Spring 数据中获取除基本聚合查询之外的任何内容(并且使用的是截至今天的最新版本 spring-data-mongodb 1.5.0.RELEASE)。

但是,使用标准 MongoDB Java 对象构建聚合查询可能会很痛苦(尤其是嵌套/复杂的情况),因为您最终会创建无数DBObject groupFields = new BasicDBObject("_id", null); 代码看起来一团糟。

我建议将以下 3 个包装器方法添加到您的代码中。

protected DBObject dbObj (String key, Object value) {
    return new BasicDBObject (key, value);
}

protected DBObject dbObj (Object ... objs) {
    DBObject dbObj = new BasicDBObject(); 
    if (objs.length % 2 == 0) {
        for (int i = 0; i < objs.length; i+=2) {
            dbObj.put((String)objs[i], objs[i+1]);          
        }
    }
    return dbObj;
}

protected DBObject dbList (Object ... objs) {
    BasicDBList dbList = new BasicDBList();
    for (Object obj : objs) {
        dbList.add(obj);
    }
    return (DBObject)dbList;
}

这使得您可以在基于 JSON 的查询和 Java 代码之间轻松进行转换。例如如果您有以下复杂查询(取自 http://docs.mongodb.org/manual/tutorial/aggregation-zip-code-data-set/ )

db.zipcodes.aggregate(
{
    $group: {
        _id: { state: "$state", city: "$city" },
        pop: { $sum: "$pop" }
    }
},{
    $sort: { pop: 1 }
},{
    $group: {
        _id: "$_id.state",
        biggestCity: { $last: "$_id.city"        },
        biggestPop: { $last: "$pop"        },
        smallestCity: { $first: "$_id.city"        },
        smallestPop: { $first: "$pop" }
    }
},{
    $project: {
        _id: 0,
        state: "$_id",
        biggestCity: {
            name: "$biggestCity",
            pop: "$biggestPop"
        },
        smallestCity: {
            name: "$smallestCity",
            pop: "$smallestPop"
        }
    }
});

...那么您的 Java 代码将如下所示...

List<DBObject> aggregation = Arrays.asList (
    dbObj ("$group", dbObj (
        "_id", dbObj ("state", "$state", "city", "$city"),
        "pop", dbObj ("$sum", "$post")
    )),
    dbObj ("$sort", dbObj ("pop", 1)),
    dbObj ("$group", dbObj (
        "_id", "$_id.state",
        "biggestCity", dbObj ("$last", "$_id.city"), 
        "biggestPop", dbObj ("$last", "$pop"),
        "smallestCity", dbObj ("$first", "$_id.city"),
        "smallestPop", dbObj ("$first", "$pop")
    )),
    dbObj ("$project", dbObj (
        "_id", 0,
        "state", "$_id",
        "biggestCity", dbObj ("name", "$biggestCity", "pop", "$biggestPop"), 
        "smallestCity", dbObj ("name", "$smallestCity", "pop", "$smallestPop")
    ))
);

// Run aggregation query
DBCollection collection = mongoTemplate.getCollection(COLLECTION_NAME);
AggregationOutput output = collection.aggregate (aggregation);

这样做,如果它在您的编辑器(例如 RoboMongo)中工作,它也会在您的 Java 代码中工作,尽管您必须手动从结果中转换对象,这并不太痛苦,即

List<MyResultClass> results = new ArrayList<MyResultClass>();
Iterator<DBObject> it = output.results().iterator(); 
while (it.hasNext()) {
    DBObject obj = it.next();
    MyResultClass result = mongoTemplate.getConverter().read(MyResultClass.class, obj);
    results.add(result);
}

但是,您可能会发现 Spring Data Aggregation 的东西确实适合您。我喜欢 Spring,并且我确实在代码的各个部分使用 Mongo Spring Data,正是聚合支持让它失望了,例如在具有多个项目的“$group”内执行“$push”似乎不起作用。我确信它会随着时间的推移而改进(以及更好的文档)。其他人也赞同这些想法,例如http://movingfulcrum.tumblr.com/post/61693014502/spring-data-and-mongodb-a-mismatch-made-in-hell - 请参阅第 4 节。

祝你编码愉快!

关于java - 聚合框架 - 组操作抛出 NumberFormatException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20982290/

相关文章:

java - 我正在尝试使用 TestNG 在 selenium 3.0.1 中启动 Firefox,但我无法做到这一点。我也使用过 setProperty

node.js - 在node js中将JWT从后端传递到前端

node.js - 蒙戈错误: can't convert from BSON type missing to Date

java - Spring Mongo > 如何从聚合中获取列表聚合操作

java - 如何更好地在OptaPlanner中应用过度约束规划?

java - 通过数据库中的 ID 查找 View (不是 findViewById)

java - netty:警告:异常捕获()事件被触发,并且它到达管道的尾部

python - 写入时出现pymongo错误

java - 如何使用 Spring Data 删除 MongoDB 中的记录

spring-boot - SpringData MongoDB @TypeAlias 升级后停止工作