问题
I am working on a customer data loader, where customers can have multiple addresses. If the customer is not found, I create it and add the address. If the customer exists, I simply add the new address, like this:
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);
This works for new customers. The problem is that when the customer already exists, the new address overwrites the existing address.
How can I add the new address to the customer, so that it will keep multiple addresses?
From what I've found, I should be able to accomplish this with a "push" via the shell. But I don't see "push" as method on the BasicDBObject.
回答1:
Your logic can be much simpler, as it turns out. You don't need to fetch customer by "email" (I'm assuming that this is your unique identifying key for Customer) just update.
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 */ );
Big problem with the way you have your logic now is it won't work multi-threaded. You can check for customer, and it won't be there. While you are constructing the object to insert it, another thread is already doing it. Since address object is an array rather than a single field, using $addToSet will add to the array if it exists, but if it's creating a new customer, then it will create address as an array.
回答2:
You want address to be a list of addresses instead of a single address document. So for new customers you want to have:
newCustomer.put("addresses", [newAddress]) customerCollection.save(newCustomer)
And for existing customers you want
customerCollection.update(newCustomer, {$push: {"addresses": newAddress}})
sorry, I don't know the java API, so you'll have to adapt the code above to create the appropriate objects
来源:https://stackoverflow.com/questions/10471553/add-multiple-sub-documents-in-mongodb