在不替换整个文档的情况下,一次更新多个对象字段(但其中的一个子集)(Spring 3.1和MongoDB的MongoTemplate)
我试图同时更新“用户”文档中的多个字段。然而,我只想更新一些字段,而不是替换整个文档,而后者似乎是我无法避免的。我使用的方法如下所示:在不替换整个文档的情况下,一次更新多个对象字段(但其中的一个子集)(Spring 3.1和MongoDB的MongoTemplate),mongodb,spring-3,Mongodb,Spring 3,我试图同时更新“用户”文档中的多个字段。然而,我只想更新一些字段,而不是替换整个文档,而后者似乎是我无法避免的。我使用的方法如下所示: public void mergeUser(User user) { Update mergeUserUpdate = new Update(); mergeUserUpdate.set("firstName", user.getFirstName()); mergeUserUpdate.set("lastName", user.getL
public void mergeUser(User user) {
Update mergeUserUpdate = new Update();
mergeUserUpdate.set("firstName", user.getFirstName());
mergeUserUpdate.set("lastName", user.getLastName());
mergeUserUpdate.set("username", user.getUsername());
mongoTemplate.updateFirst(new Query(Criteria.where("_id").is(user.getId())), mergeUserUpdate, User.class);
}
“我的用户”对象确实包含其他字段—password
字段就是其中之一—但如果在将其设置为某个值之前,立即将其替换为空字符串或完全删除。所以在数据库中,这个:
{
"_id" : ObjectId("4fc34563c3276c69248271d8"),
"_class" : "com.test.User",
"password" : "d26b7f5c0ed888e46889dd1e3d217816d070510596f495e156e9efe4b035fec5a1fe1be643955359",
"username" : "john@gmail.com",
"alias" : "john"
}
在调用mergeUser
方法后,被替换为:
{
"_id" : ObjectId("4fc34563c3276c69248271d8"),
"_class" : "com.test.User",
"username" : "john@gmail.com",
"firstName" : "John",
"lastName" : "Doe",
"address" : {
"addressLine1" : ""
}
}
如果我查看更新对象,我会看到它包含以下内容:
{$set={firstName=John, lastName=Doe, username=john@gmail.com}}
在我看来,这是正确的,根据我对MongoDB$set
函数的理解,这应该只设置指定的值。因此,我希望密码字段保持不变,其他字段也会相应地添加或更改
作为一般性的讨论点,我最终尝试实现某种“合并”功能,Spring将自动神奇地检查所提供的用户对象中存在哪些字段,并仅使用填充的值更新数据库,而不是所有字段。我认为这在理论上是可能的。有人知道这样做的好方法吗
这是我的用户对象,以防万一:
/**
* Represents an application user.
*/
@Document(collection = "users")
public class User {
@Id
private String id;
@NotEmpty( groups={ChangePasswordValidationGroup.class} )
private String password;
@Indexed
@NotEmpty
@Email
private String username;
private String firstName;
private String lastName;
private Date dob;
private Gender gender;
private Address address;
public enum Gender {
MALE, FEMALE
}
// /////// GETTERS AND SETTERS ///////////
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
上面的代码工作得很好。我犯了一个愚蠢的错误,在正确更新后,我再次保存用户对象,并用一个新文档替换它。有另一种解决方案,可以使用Spring MongoTemplate更新没有某些字段的实体:
DBObject userDBObject = (DBObject) mongoTemplate.getConverter().convertToMongoType(user);
//remove unnecessary fields
userDBObject.removeField("_id");
userDBObject.removeField("password");
//Create setUpdate & query
Update setUpdate = Update.fromDBObject(new BasicDBObject("$set", userDBObject));
mongoTemplate.updateFirst(new Query(Criteria.where("_id").is(user.getId())), setUpdate , User.class);
//Or use native mongo
//mongoTemplate.getDb().getCollection("user").update(new BasicDBObject("_id",user.getId())
, new BasicDBObject("$set", userDBObject), false, false);
因为它使用自动转换器,所以当您的实体有许多字段时,它非常有用。即使这些字段最终没有问题,它也帮助了我。文档显示使用$set操作符保存单个字段,并在保存整个对象时排除$set操作符;它没有提到对整个对象使用$set来保存对象的一部分。现在我知道这是可能的。干杯