I use Spring Data over MongoDB. I was able to save POJOs, update them. It's working fine. But now I want to flush in db only changed fields of POJO.
For example I have User entity. I create user and then update lastActiveDate from time to time.
@Document
class User {
@Id
BigInteger ID;
String email;
String name;
Date lastActiveDate;
}
User user = new User();
user.setName("User");
user.setEmail("[email protected]");
repository.save(user);
User toUpdUser = repository.findOne(userId);
toUpdUser.setLastActiveDate(new Date);
repository.save(toUpdUser );
In second save I want update only lastActiveDate field not whole user because Document update can be slow on large entities. Also I want to know changeset (at least set of updated field).
For now I didn't find API to do that. Only possibility is to handle it manually in setters (store set of changed fields and store it manually) but it looks ugly and unsupportable. Another option is using of AOP on beans to achieve same result but IFAIK Spring Data does not treat POJO as Spring bean and uses constructor so after load POJO with AOP will be just POJO.
UPD: I looking for method without explicit mongo api (or mongo-like api) call. I have entities with dozens of field and client can change almost any of them. I want to store only changed fields and be able to get changeset to perform some checks. Difference beetween entity store and field update is too big - 5ms vs 0.2ms
Of course I can create my own implementation of POJO mappers with CRUD tracker support but it already exist why not try it. And I can use another framework not only SpringData.
Spring-data doesn't support field-by-field comparison in order to figure out which fields are updated and only send those to the database. It does support only persisting non-null fields though, I find myself leveraging that when I implement PATCH
or PUT
web services. Create a $set
object with the non-null fields, and you'll keep the other part of the document intact.
You'll need to use a somewhat undocumented feature of MongoConverters
, here's an example of a PATCH
-webservice in spring-mvc
which also maintains a history of events in an "events" array on the document:
@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
will only write non-null values to BasicDBObject
.
You can use Jackson API to determine what is changed and persist POJO. Here is the code below
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); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With