【问题标题】:upsert with MongoTemplate and use of @CreatedDate/@LastModifiedDate使用 MongoTemplate 插入并使用 @CreatedDate/@LastModifiedDate
【发布时间】:2021-01-15 05:35:13
【问题描述】:

我有一个 pojo,如下所示:

@Document
public class MyPojo {
    @Id
    private String        id;
    ...
    @CreatedDate
    private ZonedDateTime createdAt;
    @LastModifiedDate
    private ZonedDateTime modifiedAt;
}

我想用以下逻辑插入一个文档:

  • 如果文档是新文档,createdAtmodifiedAt 都设置为 now
  • 如果文档已经存在,createdAt 不应更新,modifiedAt 应设置为 now

我尝试了以下代码:

MongoTemplate template = ...; // wired
MyPojo obj = new MyPojo();

template.findAndReplace(
        new Query().addCriteria(...),
        obj,
        new FindAndReplaceOptions().upsert());

这里,成员idcreatedAtmodifiedAt 未设置(因此它们是null)。

这似乎不起作用。数据库中文档 BSON 中的相应字段从不设置。

如何结合@CreatedDate@LastModifiedDate 注释来插入文档?这是可能的,还是我需要推出自己的东西。如果是后者,如何实现上述的 upsert 逻辑?

我正在使用以下配置:

@Configuration
@EnableMongoAuditing(dateTimeProviderRef = "dateTimeConverter")

这里,dateTimeProviderRef 用于支持ZonedDateTime 对象。

另外,我注意到当调用template.save(obj)template.insert(obj) 而不是findAndReplace(...)(如在我的代码sn-p 中)时,设置了createdAtmodifiedAt创造,正如预期的那样。也就是说,我相信我需要 findAndReplace(),因为我需要一个原子 upsert 发生。

【问题讨论】:

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


    【解决方案1】:

    您需要在您的@SpringBootApplication 中使用@EnableMongoAuditing 来启用审计

    @SpringBootApplication
    @EnableMongoAuditing(modifyOnCreate = false)
    public class DemoApplication {
    

    此外,不支持 ZonedDateTime。请改用 Instant。

    参考:

    查看这个工作示例:

    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.data.annotation.CreatedDate;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.annotation.LastModifiedDate;
    import org.springframework.data.mongodb.config.EnableMongoAuditing;
    import org.springframework.data.mongodb.core.FindAndReplaceOptions;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.mapping.Document;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.time.Instant;
    
    import static org.springframework.data.mongodb.core.query.Criteria.where;
    import static org.springframework.data.mongodb.core.query.Query.query;
    
    @SpringBootApplication
    @EnableMongoAuditing
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    
    @RestController
    class Ctrl {
        @Autowired
        MongoTemplate template;
    
        @GetMapping("/templ")
        void templ() throws InterruptedException {
            template.insert(new MyPojo("TOM"));
            template.insert(new MyPojo("HARRY"));
    
    
            Thread.sleep(2000);
    
            //update BOB to Robert if exists or insert new
            //should inert new
            template.findAndReplace(
                    query(where("name").is("BOB")),
                    new MyPojo("Robert"),
                    new FindAndReplaceOptions().upsert());
    
    
            Thread.sleep(2000);
    
            //update TOM to Tommy if exists or insert new
            template.findAndReplace(
                    query(where("name").is("TOM")),
                    new MyPojo("Tommy"),
                    new FindAndReplaceOptions().upsert());
    
    
            template.findAll(MyPojo.class).forEach(System.out::println);
        }
    }
    
    @Document
    @Data
    @ToString
    @NoArgsConstructor
    class MyPojo {
        public MyPojo(String name) {
            this.name = name;
        }
    
        @Id
        private String id;
        String name = "";
        @CreatedDate
        private Instant createdAt;
    
        @LastModifiedDate
        private Instant modifiedAt;
    }
    

    输出:

    MyPojo(id=5f736d33b72165754ea9fca1, name=Tommy, createdAt=2020-09-29T17:21:59.765Z, modifiedAt=null)
    MyPojo(id=5f736d33b72165754ea9fca2, name=HARRY, createdAt=2020-09-29T17:21:55.732Z, modifiedAt=null)
    MyPojo(id=5f736d352e78c143350ed0f8, name=Robert, createdAt=2020-09-29T17:21:57.748Z, modifiedAt=null)
    

    【讨论】:

    • 我检查了您的更新。我将不得不调查我的情况有什么不同。但是,您知道为什么在您的代码 sn-p 中 modifiedAt 仍然是 nullTommy 吗?看起来findAndReplace() 只是在更新非null 字段,这与@LastModifiedDate 的预期行为相冲突。
    • 如果您在代码 sn-p 中使用 findAndReplace() 更改最初的两个 insert() 操作,您还会注意到 createdAt 未填写。
    猜你喜欢
    • 2017-05-09
    • 2017-12-14
    • 2021-08-18
    • 2014-09-08
    • 2019-10-25
    • 2019-01-13
    • 2022-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多