2012-05-06 7 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

これは危険です。同じ名字の複数の顧客がいるとどうなりますか?このコードはスレッドセーフではありません.2つのスレッドが同じ顧客を作成しようとすると、重複する可能性があります。同じ住所を2回押した場合もあります。 –

+0

良い点@AsyaKamskyでは、代わりに検索キーに電子メールアドレスを使用します。また、MongoDBにデータをロードするために設計されたシングルスレッドアプリケーションです。複数の(競合する)スレッドが可能性がある場合は、スレッドの安全性をどのように考慮することをお勧めしますか? – Aaron

+0

これを行うには複数の方法があります - アプリケーションのロジックが期待する/必要とするものに依存します。電子メールを一意にするだけで、2回目の挿入は失敗しますが、アプリケーションはそれを期待し回復する必要があります。 Javaの並行処理を使用することもできますが、問題のアドレスのコピーが複数ある場合は、$ 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 */); 

あなたのロジックが今ある大きな問題は、マルチスレッドでは機能しないことです。あなたは顧客を確認することができ、それはそこにはありません。それを挿入するためにオブジェクトを構築している間、別のスレッドがすでにそれをやっています。 addressオブジェクトは単一のフィールドではなく配列なので、$ addToSetを使用すると配列にそれが存在する場合は追加されますが、新しい顧客を作成する場合は配列としてアドレスが作成されます。

+0

これは機能しました。ありがとう! – Aaron

2

住所を単一のアドレス文書ではなくアドレスのリストにします。

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

そして、あなたは

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

ごめんたい既存の顧客のために、私はJavaのAPIを知らないので、あなたはコードを適応させる必要があります:あなたが持っているしたい新規顧客のために適切なオブジェクトを作成するには

+0

ありがとう@ChrisAtLee、私はそのショットを与えるでしょう。 – Aaron

+1

このアドレスレコードが存在しないことを確認しない限り、$ pushは既存の顧客には正しくありません(マルチスレッド設定で安全でない場合でも$ addToSetを使用してください)。 $ pushは無条件で追加されます)。 –

+0

@AsyaKamskyあなたはこれを行うためのJava構文を知っていますか? – Aaron

関連する問題