mongo中的数据:
db.test2.aggregate([
{
"$project" : {
"contents" : 1,
"comments" : {
"$filter" : {
"input" : "$comments",
"as" : "item",
"cond" : {"$gt" : ['$$item.score', 2]}
},
},
"comments2" : {
"$filter" : {
"input" : "$comments2",
"as" : "item",
"cond" : {"$gt" : ["$$item.score", 5]}
}
}
}
},
{
"$project" : {
"content" : 1,
"commentsTotal" : {
"$reduce" : {
"input" : "$comments",
"initialValue" : 0,
"in" : {"$add" : ["$$value", "$$this.score"]}
}
},
"comments2Total" : {
"$reduce" : {
"input" : "$comments2",
"initialValue" : 0,
"in" : {"$add" : ["$$value", "$$this.score"]}
}
}
}
},
{$skip : 0},
{$limit: 3}
]);
<!-- language: lang-json-->
所以你可以看到,这会做到以下几点: 1,过滤得分为gt 5的评论和评论2。 2,计算注释数组中的socre总数。
我在Spring中编写聚合查询,如下所示:
AggregationExpression reduce = ArithmeticOperators.Add.valueOf("$$value").add("$$this.socre");
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.project().andExclude("_id")
.andInclude("content")
.and("comments").filter("item", ComparisonOperators.Gt.valueOf("item.score").greaterThanValue(3)).as("comments")
.and("comments2").filter("item", ComparisonOperators.Gt.valueOf("item.score").greaterThanValue(3)).as("comments2"),
Aggregation.project("comments", "comments2")
.and(ArrayOperators.Reduce.arrayOf("comments").withInitialValue("0").reduce(reduce)).as("commentsTotal")
);
当我跑起来时,它会抛出异常:
java.lang.IllegalArgumentException:无效的引用'$$ value'!
答案 0 :(得分:2)
您可以通过在$filter
操作中包装$reduce
来尝试以下聚合。
如下所示
AggregationExpression reduce1 = new AggregationExpression() {
@Override
public DBObject toDbObject(AggregationOperationContext aggregationOperationContext) {
DBObject filter = new BasicDBObject("$filter", new BasicDBObject("input", "$comments").append("as", "item").append("cond",
new BasicDBObject("$gt", Arrays.<Object>asList("$$item.score", 2))));
DBObject reduce = new BasicDBObject("input", filter).append("initialValue", 0).append("in", new BasicDBObject("$add", Arrays.asList("$$value", "$$this.socre")));
return new BasicDBObject("$reduce", reduce);
}
};
Aggregation aggregation = newAggregation(
Aggregation.project().andExclude("_id")
.andInclude("content")
.and(reduce1).as("commentsTotal")
);
答案 1 :(得分:1)
这是一个古老的问题,但是如果有人像我一样出现在这里,这就是我能够解决的方法。
在春季,您不能像这样直接访问“ $$ this ”和“ $$ value ”变量。
AggregationExpression reduce = ArithmeticOperators.Add.valueOf("$$value").add("$$this.socre");
为此,我们必须使用reduce变量枚举,如下所示:
AggregationExpression reduce = ArithmeticOperators.Add.valueOf(ArrayOperators.Reduce.Variable.VALUE.getTarget()).add(ArrayOperators.Reduce.Variable.THIS.referringTo("score").getTarget());
希望这会有所帮助!
答案 2 :(得分:0)
我不得不解决下一个任务,没有找到任何解决方案。因此,我希望我的回答对您有所帮助。
具有角色的用户(用户具有权限列表+角色列表,每个角色都有自己的权限列表,需要查找完整的权限列表):
首先,我查找角色到roleDto(例如),然后将角色的权限收集到1个列表中:
ArrayOperators.Reduce reduce = ArrayOperators.Reduce.arrayOf("$roleDto.rights")
.withInitialValue(new ArrayList<>())
.reduce(ArrayOperators.ConcatArrays.arrayOf("$$value").concat("$$this"));
由于减少,我从角色那里收集了这1项权利列表。 之后,我做:
SetOperators.SetUnion.arrayAsSet(reduce).union("$rights")
使用先前的结果。结果类型为AggregationExpression,因为AbstractAggregationExpression实现了AggregationExpression。
所以,最后我得到了这样的信息(对不起,代码混乱):
private static AggregationExpression getAllRightsForUser() {
// concat rights from list of roles (each role have list of rights) - list of list to list
ArrayOperators.Reduce reduce = ArrayOperators.Reduce.arrayOf("$roleDto.rights")
.withInitialValue(new ArrayList<>())
.reduce(ArrayOperators.ConcatArrays.arrayOf("$$value").concat("$$this"));
// union result with user.rights
return SetOperators.SetUnion.arrayAsSet(reduce).union("$rights");
}
该操作的结果可以最终在此处使用;):
public static AggregationOperation addFieldOperation(AggregationExpression aggregationExpression, String fieldName) {
return aoc -> new Document("$addFields", new Document(fieldName, aggregationExpression.toDocument(aoc)));
}
答案 3 :(得分:0)
我遇到了同样的问题,解决方案之一是创建一个自定义的Reduce函数,这是Union示例:
public class SetUnionReduceExpression implements AggregationExpression {
@Override
public Document toDocument(AggregationOperationContext context) {
return new Document("$setUnion", ImmutableList.of("$$value", "$$this"));
}
}