Search code examples
javaspring-datacouchbasespring-data-couchbase

Update Couchbase documents without overwriting @Created fields with Spring Data Auditing


I have a Couchbase document for which I'd like to enable auditing:

@Document(expiry = 0, expiryUnit = TimeUnit.DAYS, touchOnRead = true)
public class Entity {
    @Id
    @GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES, delimiter = ":")
    private String id;

    @IdAttribute(order = 0)
    private String type;

    @IdAttribute(order = 1)
    private String entityGuid;

    @Version
    private long version;
    
    private String firstName;
    
    private String lastName;
    
    private LocalDate dateOfBirth;
    
    @CreatedDate
    private LocalDateTime createTimeStamp;
    
    @LastModifiedDate
    private LocalDateTime lastUpdateTimeStamp;
    
    @CreatedBy
    private String createdBy;
    
    @LastModifiedBy
    private String lastUpdatedBy;

    ...

My configuration:

@Data
@Configuration
@EnableCouchbaseAuditing
@EnableConfigurationProperties(CouchbaseProperties.class)
public class EntityCouchConfig extends AbstractCouchbaseConfiguration {

    ...

    @Bean
    public AuditorAware<String> couchAuditing() {
        return () -> Optional.of("my-entity-service");
    }
}

It was my expectation that when performing update operations through the Couchbase template like replaceById() and upsertById(), spring-data would preserve the document's @CreatedDate and @CreatedBy fields, only updating the @LastModifiedDate and @LastModifiedBy.

This, however, seems not to be the case. When I perform an update, the document's @Created fields are updated as well. This seems counterintuitive, and would suggest that I first need to pull the document, transfer the @Created fields, and then save that, explicitly making two calls.

I have read the spring-data-couchbase documentation on auditing but it's pretty sparse on the expected behavior here.

Is retrieving the document to capture the creation info and then updating the only way to do this, or am I implementing auditing wrong?


Solution

  • So my question was based on a flawed premise, because performing Couchbase template operations like upsert() and replaceById() will never perform any auditing logic.

    To get auditing to work, it must be used in conjunction with a Couchbase Repository's save() method.

    The other important bit is that auditing won't do away with two calls to the database if your caller wants to update an entity and doesn't have the current version number and the current auditing data.

    In order for spring-data auditing to work on an update operation, you must supply an entity with all audit fields (@CreatedDate/By, @LastModifiedDate/By) and the current version number. That means if your caller doesn't have this information, you must conduct a find call to retrieve it followed by a save once you have added that data to your entity. Only then will the auditing intelligently preserve the original @Createdxx fields while updating the @Lastxx fields.