java.lang.IllegalArgumentException : Invalid reference performing aggregation in MongoDB

我收集了一个文档:

{
    "_id": ObjectId("5ab273ed31fa764560a912f8"),
    "hourNumber": 21,
    "errorSegments": [{
        "agentName": "agentX"
    },
    {
        "agentName": "agentY"
    }]
}

我正在尝试在 Spring Boot 中执行以下聚合函数,我想在其中检索与代理匹配的特定小时的“errorSegments”,该代理在 mongo shell 中工作正常:

工作 shell :
db.errorsegment.aggregate([{
    "$match": {
        "hourNumber": 21,
        "errorSegments.agentName": "agentX"
    }
},
{
    "$project": {
        "errorSegments": {
            "$filter": {
                "input": "$errorSegments",
                "as": "e",
                "cond": {
                    "$eq": ["$$e.agentName",
                    "agentX"]
                }
            }
        }
    }
},
{
    "$unwind": "$errorSegments"
},
{
    "$replaceRoot": {
        "newRoot": "$errorSegments"
    }
}])

所以它只提供输出,这是期望的结果:
{ "agentName" : "agentX" }

但是我在 spring 中的以下代码给出了错误:
MatchOperation match = Aggregation.match(Criteria.where("hourNumber").is(21).and("errorSegments.agentName").is("agentX"));

        ProjectionOperation project = Aggregation.project()
                  .and(new AggregationExpression() {

                      @Override
                        public DBObject toDbObject(AggregationOperationContext context) {

                          DBObject filterExpression = new BasicDBObject();
                          filterExpression.put("input", "$errorSegments");
                          filterExpression.put("as", "e");
                          filterExpression.put("cond", new BasicDBObject("$eq", Arrays.<Object> asList("$$e.agentName","agentX")));

                          return new BasicDBObject("$filter", filterExpression);
                      } }).as("prop");


        UnwindOperation unwind = Aggregation.unwind("$errorSegments");

        ReplaceRootOperation replaceRoot = Aggregation.replaceRoot("$errorSegments");

        Aggregation aggregation = Aggregation.newAggregation(match,project,unwind,replaceRoot);

        AggregationResults<ErrorSegment> errorSegments = mongoOps.aggregate(aggregation, SegmentAudit.class , ErrorSegment.class);

以下是日志:
java.lang.IllegalArgumentException: Invalid reference 'errorSegments'!
    at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:99) ~[spring-data-mongodb-1.10.3.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:71) ~[spring-data-mongodb-1.10.3.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.aggregation.UnwindOperation.toDBObject(UnwindOperation.java:95) ~[spring-data-mongodb-1.10.3.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.aggregation.AggregationOperationRenderer.toDBObject(AggregationOperationRenderer.java:56) ~[spring-data-mongodb-1.10.3.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.aggregation.Aggregation.toDbObject(Aggregation.java:580) ~[spring-data-mongodb-1.10.3.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1567) ~[spring-data-mongodb-1.10.3.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1502) ~[spring-data-mongodb-1.10.3.RELEASE.jar:na]

最佳答案

错误来源是您在过滤操作中使用的别名。它应该是 errorSegments 而不是 prop 但你还有其他问题。使用 fieldname 即 $ 前缀不正确。

这是更新后的聚合。您可以使用 $filter 助手。

MatchOperation match = Aggregation.match(Criteria.where("hourNumber").is(21).and("errorSegments.agentName").is("agentX"));
ProjectionOperation project = Aggregation.
            project().and(ArrayOperators.Filter.filter("errorSegments")
                    .as("e")
                    .by(ComparisonOperators.Eq.valueOf(
                            "e.agentName")
                            .equalToValue(
                                    "agentX")))
                    .as("errorSegments");
UnwindOperation unwind = Aggregation.unwind("errorSegments");
ReplaceRootOperation replaceRoot = Aggregation.replaceRoot("errorSegments");
Aggregation aggregation = Aggregation.newAggregation(match,project,unwind,replaceRoot);

下面是生成的查询。
[
  {
    "$match": {
      "hourNumber": 21,
      "errorSegments.agentName": "agentX"
    }
  },
  {
    "$project": {
      "errorSegments": {
        "$filter": {
          "input": "$errorSegments",
          "as": "e",
          "cond": {
            "$eq": [
              "$$e.agentName",
              "agentX"
            ]
          }
        }
      }
    }
  },
  {
    "$unwind": "$errorSegments"
  },
  {
    "$replaceRoot": {
      "newRoot": "$errorSegments"
    }
  }
]