Spring 数据 MongoDB 聚合 - 按计算值匹配
Spring Data MongoDB aggregation - match by calculated value
我有一个包含 2 个数字字段的文档集合,我需要根据计算条件过滤所有文档:
Number1/Number2 >= CONST%
如何使用 Spring 数据 Mongo 和聚合来实现这一点?
--更新--
我试过以下代码:
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")
)
)
);
但是出现错误"Unrecognized parameter to $cond: $or"
您能协助解决这个问题吗?
您需要的是 $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
到 "remove" 条件为假的文档。
此操作类似于让 $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
使用效率更高的单个流水线阶段。
考虑以下演示上述概念的示例:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gte": [
{ "$divide": ["$Number1", "$Number2"] },
CONSTANT_VAR
]
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
因为有 no support for the $redact
operator yet(在撰写本文时),解决方法是实现一个 AggregationOperation
接口,该接口用 class 包装聚合操作以接收 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
:
中使用
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);
--更新--
Follow-up 从注释中检查 Number2
字段中的空值或零值,您必须嵌套 $cond
用逻辑代替表达式。
如果 Number2
不为 exist/is 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"
)
)
)
)
);
我有一个包含 2 个数字字段的文档集合,我需要根据计算条件过滤所有文档:
Number1/Number2 >= CONST%
如何使用 Spring 数据 Mongo 和聚合来实现这一点?
--更新--
我试过以下代码:
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")
)
)
);
但是出现错误"Unrecognized parameter to $cond: $or" 您能协助解决这个问题吗?
您需要的是 $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
到 "remove" 条件为假的文档。
此操作类似于让 $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
使用效率更高的单个流水线阶段。
考虑以下演示上述概念的示例:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gte": [
{ "$divide": ["$Number1", "$Number2"] },
CONSTANT_VAR
]
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
因为有 no support for the $redact
operator yet(在撰写本文时),解决方法是实现一个 AggregationOperation
接口,该接口用 class 包装聚合操作以接收 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
:
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);
--更新--
Follow-up 从注释中检查 Number2
字段中的空值或零值,您必须嵌套 $cond
用逻辑代替表达式。
如果 Number2
不为 exist/is 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"
)
)
)
)
);