使SpringData更新只更改POJO的字段

时间:2015-09-17 17:36:14

标签: java spring mongodb spring-data spring-data-mongodb

我在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。

4 个答案:

答案 0 :(得分:4)

Spring-data不支持逐字段比较,以便确定哪些字段已更新,并仅将这些字段发送到数据库。我确实只支持持久化的非空字段,当我实现PATCHPUT 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将这样做的用法合并到存储库中,使用该机制来实现此处所述的各个查询方法。