2012-05-06 4 views
1

고객이 여러 주소를 가질 수있는 고객 데이터 로더를 작성 중입니다. 고객을 찾지 못하면 고객 정보를 작성하고 주소를 추가합니다. 고객이있는 경우 다음과 같이 새 주소를 추가하면됩니다.MongoDB에 여러 하위 문서 추가

DBObject findCustomer = new BasicDBObject(); 
    findCustomer.put("email", custEmail); 

    //check for existing customer 
    DBObject newCustomer = customerCollection.findOne(findCustomer); 

    if (newCustomer == null) { 
     //INSERT  
     newCustomer = new BasicDBObject(); 
     newCustomer.put("firstname", firstname); 
     newCustomer.put("lastname", lastname); 
     newCustomer.put("email", custEmail); 
     newCustomer.put("password", custData.getPassword()); 
     newCustomer.put("softwaretime", new Date()); 
    } 

    DBObject newAddress = new BasicDBObject(); 
    City tempCity = new City(); 
    tempCity = addressData.getCity(); 

    newAddress.put("type", addressData.getType()); 
    newAddress.put("line1", addressData.getLine1()); 
    newAddress.put("line2", addressData.getLine2()); 
    newAddress.put("city", tempCity.getCity()); 
    newAddress.put("state", tempCity.getState()); 
    newAddress.put("postal", tempCity.getZip()); 
    newAddress.put("country", tempCity.getCountry()); 

    newCustomer.put("address", newAddress); 

    customerCollection.save(newCustomer); 

이것은 신규 고객에게 유용합니다. 문제는 고객이 이미 존재하면 새 주소가 기존 주소를 덮어 씁니다.

새 주소를 고객에게 추가하여 여러 주소를 유지하려면 어떻게해야합니까?

내가 발견 한 것부터, 나는 이것을 쉘을 통해 "밀어 넣기"로 수행 할 수 있어야합니다. 하지만 BasicDBObject에서 메서드로 "push"하는 것을 보지 못했습니다.

+0

위험한 것처럼 보입니다. 이름과 성이 동일한 고객이 여러 명일 경우 어떻게됩니까? 이 코드는 스레드로부터 안전하지 않습니다. 두 스레드가 동일한 고객을 만들려고하면 중복 될 수 있습니다. 동일한 주소가 두 번 푸시되었을 수도 있습니다. –

+0

좋은 지적 @AsyaKamsky, 대신 검색 키에 이메일 주소를 사용하겠습니다. 또한 MongoDB에 데이터를로드하기 위해 설계된 단일 스레드 응용 프로그램입니다. 여러 (경쟁하는) 스레드가있을 가능성이있는 경우 스레드 안전을 어떻게 고려해야할까요? – Aaron

+0

여러 가지 방법이 있습니다 - 응용 프로그램 논리가 필요로하는 것이 무엇인지에 따라 다릅니다. 전자 메일을 고유하게 만들 수 있으며 두 번째 삽입 시도가 실패하지만 응용 프로그램에서이를 예상하고 복구해야합니다. 자바 동시성을 사용할 수는 있지만 문제가되는 주소의 사본이 여러 개인 경우 $ push 대신 $ addToSet을 사용하면 이미 목록에있는 주소가 추가되지는 않습니다. –

답변

1

논리가 훨씬 간단해질 수 있습니다. "전자 메일"로 고객을 가져올 필요가 없습니다 (고객이 고유 한 식별 키라고 가정합니다).

findCustomer.put("email", custEmail); // search query for the customer email 

// construct your newAddress object the same way you already are 

BasicDBObject custMod = new BasicDBObject(); 
custMod.put("$addToSet", newAddress); 
customerCollection.update(findCustomer, custMod, true /* upsert */, false /* multi */); 

논리가 큰 문제는 이제 멀티 스레드로 작동하지 않는다는 것입니다. 당신은 고객을 확인할 수 있으며 거기에 없을 것입니다. 그것을 삽입하기 위해 객체를 생성하는 동안 다른 스레드가 이미 그것을 수행하고 있습니다. 주소 개체는 단일 필드가 아닌 배열이므로 $ addToSet을 사용하면 배열에 추가 할 수 있지만 새 고객을 만드는 경우 주소를 배열로 만듭니다.

+0

이것은 효과가 있습니다. 감사! – Aaron

2

주소를 단일 주소 문서 대신 주소 목록으로 지정합니다. 그래서 새로운 고객을위한 당신이 갖고 싶어 : 코드를 적용해야합니다 있도록

 
newCustomer.put("addresses", [newAddress]) 
customerCollection.save(newCustomer) 

을 그리고 기존 고객에 대한 당신이

 
customerCollection.update(newCustomer, {$push: {"addresses": newAddress}}) 

죄송합니다, 나는 자바 API를 모르는 적절한 객체를 만들려면 위의 내용을 참조하십시오.

+0

고마워요 .ChrisAtLee, 내가 그걸 줄께. – Aaron

+1

$ push는 기존의 고객에게는 맞지 않습니다.이 주소 레코드가 존재하지 않는다는 것을 확인하지 않으면 (만약 멀티 스레드 설정에서 안전하지 않다면) $ addToSet을 대신 사용하십시오. 아직 거기에 없으면 $ push는 무조건 추가합니다). –

+0

@AsyaKamsky 일을하기 위해 Java 구문을 알고 있습니까? – Aaron

관련 문제