我在MongoDB上使用Spring Data。我能够保存POJO,更新它们。它工作正常。但是现在我想在db中仅刷新POJO的更改字段。
例如我有User实体。我创建用户,然后不时更新lastActiveDate。
@Document
class User {
@Id
BigInteger ID;
String email;
String name;
Date lastActiveDate;
}
User user = new User();
user.setName("User");
user.setEmail("example@example.com");
repository.save(user);
User toUpdUser = repository.findOne(userId);
toUpdUser.setLastActiveDate(new Date);
repository.save(toUpdUser );
在第二次保存中,我希望仅更新lastActiveDate字段而不是整个用户,因为文档更新在大型实体上可能很慢。另外我想知道changeset(至少是更新字段集)。
目前我还没有找到API来做到这一点。唯一的可能性是在setter中手动处理它(存储已更改字段的集合并手动存储)但它看起来很丑陋且不受支持。另一种选择是在bean上使用AOP来实现相同的结果,但是IFAIK Spring Data不会将POJO视为Spring bean并且使用构造函数,因此在使用AOP加载POJO之后将只是POJO。
UPD: 我正在寻找没有明确的mongo api(或mongo-like api)调用的方法。我有几十个领域的实体,客户几乎可以改变任何一个。我想只存储已更改的字段,并能够获取更改集以执行某些检查。实体存储和字段更新之间的差异太大 - 5ms vs 0.2ms
当然我可以使用CRUD跟踪器支持创建自己的POJO映射器实现,但它已经存在,为什么不尝试它。而且我不仅可以使用另一个框架SpringData。
答案 0 :(得分:4)
Spring-data不支持逐字段比较,以便确定哪些字段已更新,并仅将这些字段发送到数据库。我确实只支持持久化的非空字段,当我实现PATCH
或PUT
Web服务时,我发现自己会利用它。使用非空字段创建$set
对象,并保持文档的其他部分不变。
您需要使用MongoConverters
的某种未记录的功能,这里是PATCH
的一个例子 - spring-mvc
中的网络服务,它也保留了事件"事件"文档上的数组:
@RestController
public class MyWebservice {
@Autowired
private MongoConverter mongoConverter;
@RequestMapping(value = "/order/{id}", method = PATCH, produces = APPLICATION_JSON_UTF8_VALUE, consumes = APPLICATION_JSON_UTF8_VALUE)
public Order updateOrder(@PathVariable("id") String id, @RequestBody Order order) throws JsonProcessingException {
order.setId(id);
DBObject update = getDbObject(order);
mongoTemplate.updateFirst(query(where("id").is(id)), Update.fromDBObject(new BasicDBObject("$set", update)).push("events", order), Order.class);
return mongoTemplate.findOne(query(where("id").is(id)), Order.class);
}
private DBObject getDbObject(Object o) {
BasicDBObject basicDBObject = new BasicDBObject();
mongoConverter.write(o, basicDBObject);
return basicDBObject;
}
}
MongoConverter
只会将非空值写入BasicDBObject
。
答案 1 :(得分:1)
您可以使用Jackson API来确定更改内容并保留POJO。这是下面的代码
public class TestJacksonUpdate {
class Person implements Serializable {
private static final long serialVersionUID = -7207591780123645266L;
public String code = "1000";
public String firstNm = "John";
public String lastNm;
public Integer age;
public String comments = "Old Comments";
@Override
public String toString() {
return "Person [code=" + code + ", firstNm=" + firstNm + ", lastNm=" + lastNm + ", age=" + age
+ ", comments=" + comments + "]";
}
}
public static void main(String[] args) throws JsonProcessingException, IOException {
TestJacksonUpdate o = new TestJacksonUpdate();
String input = "{\"code\":\"10000\",\"lastNm\":\"Smith\",\"comments\":\"Jackson Update WOW\"}";
Person persist = o.new Person();
System.out.println("persist: " + persist);
ObjectMapper mapper = new ObjectMapper();
Person finalPerson = mapper.readerForUpdating(persist).readValue(input);
System.out.println("Final: " + finalPerson);
// repository.save(finalPerson); } }
答案 2 :(得分:0)
您正在寻找MongoTemplate.updateFirst()
请在此处查看相关答案:Spring Data Mongodb: Updating documents
答案 3 :(得分:-1)
要更新对象的各个字段,请使用reference documentation中所述的Update
API。然后可以使用MongoTemplate
将这样做的用法合并到存储库中,使用该机制来实现此处所述的各个查询方法。