2014-06-13 3 views
0

MongoDB에는 고객 정의 레이블을 포함하는 Customer라는 문서 모음이 있습니다. 내 도메인 객체 (롬복 주석 포함)과 같이 :스프링 데이터 REST에 임베디드 문서의 링크 관계에 대한 내 욕구를 어떻게 알릴 수 있습니까?

@Document(collection = "Customer") 
@Getter 
@Setter 
public class Customer { 
    @Id 
    long id; 

    @Field("name") 
    String name; 

    @Field("labels") 
    List<CustomerLabel> labels; 
} 

@Getter 
@Setter 
public class CustomerLabel { 

    @Id 
    @Field("label_id") 
    long labelId; 

    @Field("label_name") 
    String labelName; 
} 

지금 GET /customers에 대한 응답은 다음과 같습니다

{ 
    "_links": { 
    "self": { 
     "href": "http://localhost:8080/app/customers?page=&size=&sort=" 
    } 
    }, 
    "_embedded": { 
    "customers": [ 
     { 
     "name": "Smith, Jones, and White", 
     "labels": [ 
      { 
      "labelName": "General label for Smith, Jones, and White" 
      } 
     ], 
     "_links": { 
      "self": { 
      "href": "http://localhost:8080/app/customers/285001" 
      } 
     } 
     } 
    ] 
    }, 
    "page": { 
    "size": 20, 
    "totalElements": 1, 
    "totalPages": 1, 
    "number": 0 
    } 
} 
내가 포함 된 라벨 문서로 "불러"하고 싶은

{ 
    "_links": { 
    "self": { 
     "href": "http://localhost:8080/app/customers?page=&size=&sort=" 
    } 
    }, 
    "_embedded": { 
    "customers": [ 
     { 
     "name": "Smith, Jones, and White", 
     "_links": [ 
      { 
      "labels": { 
      "href": "http://localhost:8080/app/customers/285001/labels" 
      }, 
      { 
      "self": { 
      "href": "http://localhost:8080/app/customers/285001" 
      } 
     }] 
     } 
    ] 
    }, 
    "page": { 
    "size": 20, 
    "totalElements": 1, 
    "totalPages": 1, 
    "number": 0 
    } 
} 

가 어떻게 내 응용 프로그램에서이 작업을 수행 할 수 있습니다 별도의 연결 관계는, 그래서 GET /customers에 대한 응답은 다음과 같이 더 본다?

답변

0

ResourceProcessor을 구현하여 Repository REST 컨트롤러에서 반환 된 Resource 개체의 레이블을 제거했습니다. 그것은 다음과 같습니다

@Controller 
@AllArgsConstructor(onConstructor = @__(@Inject)) 
class CustomerResourceProcessor implements ResourceProcessor<Resource<Customer>> { 

    private final @NonNull CustomerLinks customerLinks; 

    @Override 
    public Resource<Customer> process(Resource<Customer> resource) { 
     Customer customer = resource.getContent(); 
     if (customer.getLabels() != null && !customer.getLabels().isEmpty()) { 
      resource.add(customerLinks.getLabelCollectionLink(resource)); 
      customer.setLabels(null); 
     } 
     return resource; 
    } 
} 

가 그럼 난 내가 본 RESTBucks 예제의 방식으로 LabelController을 썼다 :

@ResponseBody 
@RequestMapping(value = "/customers/{customerId}/labels", method = RequestMethod.GET) 
Resources<LabelResource> labels(@PathVariable Long customerId) { 
    List<CustomerLabel> customerLabels = customerRepository.findLabelsByCustomerId(customerId); 
    return new Resources<>(resourceAssembler.toResources(customerLabels), linkTo(
      methodOn(this.getClass()).labels(customerId)).withSelfRel()); 
} 

그리고 CustomerRepositoryfindLabelsByCustomerId 방법은 사용자 정의 저장소 메소드 구현되는 Mongo의 labels 필드 만 반환합니다.

최소한의 코드로 모두 잘 작동합니다. 그 트릭은 정확히 인데, 나는 코드를 써야했습니다. :)

0

나는 이것이 일종의 차선 설계라고 주장한다. MongoDB로 작업 할 때, 모델링 된 문서는 기본적으로 컨셉이 잘 정렬되어 (관련 집계/문서 간의 최종 일관성을 수용하여) 도메인 기반 디자인이라는 용어로 집계됩니다.

리포지토리는 집계 모음 (MongoDB에서 읽음 : 문서)을 시뮬레이션합니다. 따라서 임베디드 문서 저장소 (귀하의 경우 CustomerLabel)가 실제로 너무 많은 의미를 갖지는 않습니다. 또한, CustomerCustomerLabels을 동일한 컬렉션에 지속시키지 만 후자가 내게 의심스럽게 보이는 것처럼 보입니다.

그래서 스프링 데이터를 통해 문서를 노출하는 방법보다 MongoDB 스키마 디자인 문제가 더 많은 것 같습니다. 즉, 내가 말한 것처럼 만족스러운 답을 얻으려는 것이 확실하지 않다는 것입니다. 제기 한 질문은 코드베이스에서보다 근본적인 문제를 가리는 것으로 보입니다.

+0

당신의 제안은 데이터베이스 구조에 링크 관계를 더 밀접하게 연결하는 것입니다. 나는 그것을 잘못 읽고 있습니까? 그것은 차선 설계의 사례가 아닐까요? –

+0

아니요, 링크 관계의 수준이 아닙니다. 나는 class-to-document-mapping이 최선의 방법보다 차선책이라고 주장한다. 임베디드 문서 저장소를 갖는 것은 집계 디자인 원칙을 완전히 위반하는 것입니다. 어떤 종류의 웹 서비스를 구축하고 싶은지는 완전히 직관적 인 질문입니다. 그러나 근본적으로 잘못 설계된 무언가의 바로 위에 무언가를하려고하면 어떤 방법으로도 작동하지 않습니다. :) –

+0

죄송합니다. 이해하려고합니다. 임베디드 문서 자체가 차선 설계라고 주장하거나, 저장소가 아닌 다른 것을 반환하는 것이 차선책 일 것이라고 말하고 있습니까? –