我正在使用Spring-Data MongoDB aggregation framework
。
以下是代码示例:
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
是locale字段的值,但我不明白为什么抛出该异常。
我正在使用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" }
答案 0 :(得分:3)
我的简单回答是避免直接使用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,它是聚合支持,例如做一个&#34; $ push&#34;在&#34; $ group&#34;有多个项目似乎没有用。我确信它会随着时间的推移而改进(以及更好的文档)。其他人也回应了这些想法,例如: http://movingfulcrum.tumblr.com/post/61693014502/spring-data-and-mongodb-a-mismatch-made-in-hell - 请参阅第4节。
快乐的编码!