Spring Data MongoDB聚合

编程入门 行业动态 更新时间:2024-10-20 18:49:32
Spring Data MongoDB聚合 - 按计算值匹配(Spring Data MongoDB aggregation - match by calculated value)

我有一个包含2个数字字段的文档集合,我需要根据计算的条件过滤所有文档:

Number1/Number2 >= CONST%

如何使用Spring Data Mongo和Aggregation创建这个?

--UPDATE--

我试过以下代码:

return new RedactAggregationOperation( new BasicDBObject( "$redact", new BasicDBObject( "$cond", new BasicDBObject() .append("if", new BasicDBObject( "$gte", Arrays.asList(new BasicDBObject( "$divide", Arrays.asList( "$Number1", new BasicDBObject( "$cond", new BasicDBObject() .append("$or", Arrays.asList( new BasicDBObject( "$eq", new BasicDBObject( "$Number2", 0)), new BasicDBObject( "$eq", new BasicDBObject( new BasicDBObject( "$ifNull", new BasicDBObject( "$Number2", 0)).toString(), 0)))) .append("then", 1000000) .append("else", "$Number2")), CONSTANT_VAR)) ))) .append("then", "$$KEEP") .append("else", "$$PRUNE") ) ) );

但是有一个错误“无法识别参数$ cond:$或”你能否协助解决这个问题?

I've got a collection of documents with 2 Number fields and I need to filter all the documents based on a calculated condition:

Number1/Number2 >= CONST%

How can I make this posible using Spring Data Mongo and Aggregation?

--UPDATE--

I've tried the following code:

return new RedactAggregationOperation( new BasicDBObject( "$redact", new BasicDBObject( "$cond", new BasicDBObject() .append("if", new BasicDBObject( "$gte", Arrays.asList(new BasicDBObject( "$divide", Arrays.asList( "$Number1", new BasicDBObject( "$cond", new BasicDBObject() .append("$or", Arrays.asList( new BasicDBObject( "$eq", new BasicDBObject( "$Number2", 0)), new BasicDBObject( "$eq", new BasicDBObject( new BasicDBObject( "$ifNull", new BasicDBObject( "$Number2", 0)).toString(), 0)))) .append("then", 1000000) .append("else", "$Number2")), CONSTANT_VAR)) ))) .append("then", "$$KEEP") .append("else", "$$PRUNE") ) ) );

But there is an error "Unrecognized parameter to $cond: $or" Could you please assist with this issue?

最满意答案

您需要的是聚合框架中的$redact运算符,它允许您使用$cond运算符处理上述逻辑条件,并使用特殊操作$$KEEP来“保留”逻辑条件为真的文档或$$PRUNE “删除”条件为假的文档。

此操作类似于具有$project管道,该管道选择集合中的字段并创建一个新字段,该字段保存逻辑条件查询的结果,然后是后续的$match ,但$redact使用单个管道阶段更多高效。

考虑以下示例演示上述概念:

db.collection.aggregate([ { "$redact": { "$cond": [ { "$gte": [ { "$divide": ["$Number1", "$Number2"] }, CONSTANT_VAR ] }, "$$KEEP", "$$PRUNE" ] } } ])

由于目前还没有对$redact运算符的支持 (在编写本文时),解决方法是实现一个AggregationOperation接口,该接口将聚合操作包装在一个类中以接收DBObject :

public class RedactAggregationOperation implements AggregationOperation { private DBObject operation; public RedactAggregationOperation (DBObject operation) { this.operation = operation; } @Override public DBObject toDBObject(AggregationOperationContext context) { return context.getMappedObject(operation); } }

然后你可以在TypeAggregation使用TypeAggregation :

Aggregation agg = newAggregation( new RedactAggregationOperation( new BasicDBObject( "$redact", new BasicDBObject( "$cond", new BasicDBObject() .append("if", new BasicDBObject( "$gte", Arrays.asList( new BasicDBObject( "$divide", Arrays.asList( "$Number1", "$Number2" ) ), CONSTANT_VAR ) ) ) .append("then", "$$KEEP") .append("else", "$$PRUNE") ) ) ) ); AggregationResults<Example> results = mongoTemplate.aggregate( (TypedAggregation<Example>) agg, Example.class);

--UPDATE--

从注释中跟进,要检查除法中Number2字段的空值或零值,您必须使用逻辑嵌套$cond表达式。

以下示例假定如果Number2不存在/为null或值为零,则占位符值为1:

db.collection.aggregate([ { "$redact": { "$cond": [ { "$gte": [ { "$divide": [ "$Number1", { "$cond": [ { "$or": [ { "$eq": ["$Number2", 0] }, { "$eq": [ { "$ifNull": ["$Number2", 0] }, 0 ] } ] }, 1, // placeholder value if Number2 is 0 "$Number2" ] } ] }, CONSTANT_VAR ] }, "$$KEEP", "$$PRUNE" ] } } ])

等效Spring数据聚合(未经测试)

Aggregation agg = newAggregation( new RedactAggregationOperation( new BasicDBObject( "$redact", new BasicDBObject( "$cond", Arrays.asList( new BasicDBObject( "$gte", Arrays.asList( new BasicDBObject( "$divide", Arrays.asList( "$Number1", new BasicDBObject( "$cond", Arrays.asList( new BasicDBObject( "$or": Arrays.asList( new BasicDBObject("$eq", Arrays.asList("$Number2", 0)), new BasicDBObject("$eq", Arrays.asList( new BasicDBObject("$ifNull", Arrays.asList("$Number2", 0)), 0 ) ) ) ), 1, // placeholder value if Number2 is 0 "$Number2" ) ) ) ), CONSTANT_VAR ) ), "$$KEEP", "$$PRUNE" ) ) ) ) );

What you need is the $redact operator in the aggregation framework which allows you to proccess the above logical condition with the $cond operator and uses the special operations $$KEEP to "keep" the document where the logical condition is true or $$PRUNE to "remove" the document where the condition was false.

This operation is similar to having a $project pipeline that selects the fields in the collection and creates a new field that holds the result from the logical condition query and then a subsequent $match, except that $redact uses a single pipeline stage which is more efficient.

Consider the following example which demonstrate the above concept:

db.collection.aggregate([ { "$redact": { "$cond": [ { "$gte": [ { "$divide": ["$Number1", "$Number2"] }, CONSTANT_VAR ] }, "$$KEEP", "$$PRUNE" ] } } ])

Since there's no support for the $redact operator yet (at the time of writing), a workaround will be to implement an AggregationOperation interface that wraps the aggregation operation with a class to take in a DBObject:

public class RedactAggregationOperation implements AggregationOperation { private DBObject operation; public RedactAggregationOperation (DBObject operation) { this.operation = operation; } @Override public DBObject toDBObject(AggregationOperationContext context) { return context.getMappedObject(operation); } }

which you can then use in TypeAggregation:

Aggregation agg = newAggregation( new RedactAggregationOperation( new BasicDBObject( "$redact", new BasicDBObject( "$cond", new BasicDBObject() .append("if", new BasicDBObject( "$gte", Arrays.asList( new BasicDBObject( "$divide", Arrays.asList( "$Number1", "$Number2" ) ), CONSTANT_VAR ) ) ) .append("then", "$$KEEP") .append("else", "$$PRUNE") ) ) ) ); AggregationResults<Example> results = mongoTemplate.aggregate( (TypedAggregation<Example>) agg, Example.class);

--UPDATE--

Follow-up from the comments, to check for nulls or zero values on the Number2 field in the division, you would have to nest a $cond expression with the logic instead.

The following example assumes you have a placeholder value of 1 if either Number2 does not exist/is null or have a value of zero:

db.collection.aggregate([ { "$redact": { "$cond": [ { "$gte": [ { "$divide": [ "$Number1", { "$cond": [ { "$or": [ { "$eq": ["$Number2", 0] }, { "$eq": [ { "$ifNull": ["$Number2", 0] }, 0 ] } ] }, 1, // placeholder value if Number2 is 0 "$Number2" ] } ] }, CONSTANT_VAR ] }, "$$KEEP", "$$PRUNE" ] } } ])

Equivalent Spring Data Aggregation (untested)

Aggregation agg = newAggregation( new RedactAggregationOperation( new BasicDBObject( "$redact", new BasicDBObject( "$cond", Arrays.asList( new BasicDBObject( "$gte", Arrays.asList( new BasicDBObject( "$divide", Arrays.asList( "$Number1", new BasicDBObject( "$cond", Arrays.asList( new BasicDBObject( "$or": Arrays.asList( new BasicDBObject("$eq", Arrays.asList("$Number2", 0)), new BasicDBObject("$eq", Arrays.asList( new BasicDBObject("$ifNull", Arrays.asList("$Number2", 0)), 0 ) ) ) ), 1, // placeholder value if Number2 is 0 "$Number2" ) ) ) ), CONSTANT_VAR ) ), "$$KEEP", "$$PRUNE" ) ) ) ) );

更多推荐

本文发布于:2023-08-05 10:57:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1431185.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Spring   Data   MongoDB

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!