2014-04-29 1 views
2

이 예제 집계는 IllegalArgumentException을 던집니다. 'role'이 잘못되었습니다!투영 후 그룹 집계를 만드는 동안 참조가 잘못되었습니다.

투영 단계 이후에 필드의 이름을 바꾸고 나면 매번이 문제가 발생합니다.

final Aggregation aggregation = newAggregation(

      // We only like to have the "company" and "empolyee.role" renamed to "role" 
      project("company") 
        .and("employee.role").as("role"), 

      // Group by the **renamed** "role" 
      group("role").count().as("count"), // this will fail because "role" is an invalid reference. 
      limit(2) 
      ); 

    return aggregation; 

우리는 다음과 같다 작업중인 JSON :

{ 
    // some fields 
    company : { 
      // some fields 
    } 

    employee : { 
      role : { 
        // some fields 
      } 

    } 
} 

생각 :

Here 올리버 그것은 당신이 집계를 정의하는 것이 이해하는 것이 중요

말했다 문서 필드 이름이 아닌 유형 특성 용어.

예외가 발생하는 이유는 무엇입니까? 그렇다면, 어떻게 좋은 aggegration API를 봄 데이터를 제공하는 사용합니다.

업데이트 : :

이 전 버전 1.5.0.M1으로 얻을 스택 트레이스입니다 :

java.lang.IllegalArgumentException: Invalid reference 'role'! 
    at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:78) 
    at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:62) 
    at org.springframework.data.mongodb.core.aggregation.GroupOperation.toDBObject(GroupOperation.java:292) 
    at org.springframework.data.mongodb.core.aggregation.Aggregation.toDbObject(Aggregation.java:247) 
    at com.xxx.report.adapter.AggrigateByTopic.aggrigateBy(AggrigateByTopic.java:38) 
    at com.xxx.report.adapter.AggrigateByTopicTest.shouldAggrigate(AggrigateByTopicTest.java:38) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
+0

어떤 버전을 사용하고 있습니까? 정확한 스택 추적은 무엇입니까? –

+0

스택 트레이스에 1.5.0.M1을 추가했습니다. (이전 버전과 동일 함) – d0x

답변

2

구현이 필드 앨리어싱 유형을 "좋아하지 않는다"사실이다 당신이 여기에서하고 있다고 말입니다. 그러나 가장 엄격한 해석에서, 당신이하는 일은별로 의미가 없습니다.

귀하의 문을해야 뭔가 같은 :로 파이프 라인을 생산

final Aggregation aggregation = newAggregation(
      group("employee.role").count().as("count"), 
      sort(Sort.Direction.DESC,"count"), 
      limit(2) 
    ); 

    System.out.println(aggregation); 

:

{ 
    "aggregate" : "__collection__", 
    "pipeline" : [ 
     { "$group" : { 
      "_id" : "$employee.role", 
      "count" : { "$sum" : 1} 
     }}, 
     { "$sort" : { "count" : -1} }, 
     { "$limit" : 2} 
    ] 
} 

점 여기 $project 사용이 정말 선택 이외의 아무것도되지 않는다는 것을 나중에 사용하지 않는 필드 하나를 사용하고 실제로 사용하지 않는 다른 필드의 별칭을 만들면 그룹화에 대한 _id 필드가됩니다. 당신이 예상 위해 일을하지 않는 한 정말 $limit에 많은 이해가되지 않으며, $group 자체적으로 그렇게하지 않는 한 또한 $sort의 사용을 확인합니다. 정말의 팬이 아니다 "속성"개념을 설명하기위한로서

, 당신은 다음과 같은 코드를 고려해 볼 수 있습니다 : 다음

final Aggregation aggregation = newAggregation(
      group("country","employee.role").count().as("count"), 
      group("employee.role","count").count().as("totalCount"), 
      sort(Sort.Direction.DESC,"totalCount"), 
      limit(2) 
    ); 

    System.out.println(aggregation); 

을 다음과 같이 보일 것이다 구성되어 파이프 라인 :

{ 
    "aggregate" : "__collection__", 
    "pipeline" : [ 
     { "$group" : { 
      "_id" : { 
       "country" : "$country" , 
       "role" : "$employee.role" 
      }, 
      "count" : { "$sum" : 1} 
     }}, 
     { "$group" : { 
      "_id" : { 
       "role" : "$_id.employee.role" , 
       "count" : "$count" 
      }, 
      "totalCount" : { "$sum" : 1} 
     }}, 
     { "$sort" : { "totalCount" : -1} }, 
     { "$limit" : 2 } 
    ] 
} 

예외없이 표시된대로 출력 덤프까지 실행되는 동안 생성 된 파이프 라인에는 여전히 문제가 있습니다.첫 번째 $group 문은 하위 문서 필드의 별칭을 압축하지만이 시점에서 문제가 없으면 두 번째 $group 단계가 문제를 일으 킵니다.

전체 "employee.role"표기법을 사용하여 해당 필드를 원본 문서의 속성으로 참조하지 않는 한 빌더 메소드는 "불만"합니다. 그리고 이것이 이전 단계의 _id 필드의 일부가 될 수도 있지만, 필드에 별명이 있음을 완전히 잊었습니다.

내 두 센트의 경우, 이것이 잘못된 행동이고 내가 왜 건축가의 큰 팬이 아닌지에 대한 강한 이유입니다.

그래도 사용할 수는 있지만 아직 디자인이 완전히 결함이 아니라고 생각됩니다. 다시 말하지만, 돈을 위해 DBObject 유형을 사용하여 파이프 라인을 구성하고 완료하는 것이 더 안전하고 유연 해 보입니다. 적어도 당신은 항상 당신이 의미하는 바를 정확히 알 수 있습니다.

+0

예, 맞습니다. 나는이 예에서 "쓸모없는"투사를한다. 나는 그 당시 질문을 쓰는 것을 보지 못했습니다. 어쨌든, 중요한 것은 ** 유형 **에 대한 투영 이후 다른 그룹 스테이지에서 투영 된 "필드"를 사용할 수 없다는 것입니다. – d0x

+0

@ChristianSchneider 네. 그리고 내가 지적하고자하는 핵심은 현재 API에서이 문제가 있다는 것입니다. 대신 DBObject 생성 양식을 사용하십시오. 또한 API가 작동하는 것처럼 다르게 진술을 작성한다면 요점이 있습니다. 어느 쪽이든, 확실히 확실한 답이 될 것 같습니다. –