Enable auditing with Spring Data MongoDB. For example with Spring Data JPA, visit Spring Data JPA Audit Example.

Background

Spring Data MongoDB provides auditing support for MongoDB. Auditing is a common requirement for most applications. It is used to track changes to entities, such as who created or modified an entity and when the change occurred.

In this example, we will create a simple Spring Boot application that uses Spring Data MongoDB to persist and retrieve data from MongoDB. We will also enable auditing to track changes to entities.

Document Class

We will have a Document called User:

@Document
class User {

    @Id
    private ObjectId id;

    private String name;

    private String username;

    @CreatedBy
    private String createdBy;

    @CreatedDate
    private Instant created;

    @LastModifiedBy
    private String modifiedBy;

    @LastModifiedDate
    private Instant modified;

    // getters and setters
}

Fields that are marked with @CreatedBy, @CreatedDate, @LastModifiedBy and @LastModifiedDate are meant for auditing and will be populated by Spring Data MongoDB.

Enable Mongo Audit

To enable auditing, we need to add @EnableMongoAuditing annotation to our @Configuration class - MongoAuditConfiguration:

@Configuration
@EnableMongoAuditing
class MongoAuditConfiguration {

    @Bean
    public AuditorAware<String> auditorAwareRef() {
        return () -> Optional.of("Mr. Auditor");
    }

}

Verify Audit Implementation

We will verify that the auditing is working by creating a test case that will create a new User and verify that the created, createdBy, modified, and modifiedBy fields are populated.

@Testcontainers
@DataMongoTest(includeFilters = @Filter(type = ANNOTATION, classes = EnableMongoAuditing.class))
class UserAuditTests {

    @Container
    @ServiceConnection
    private final static MongoDBContainer mongo = new MongoDBContainer("mongo:latest");

    @Autowired
    private UserRepository repository;

    @Test
    @DisplayName("When a user is saved Then created and modified fields are set And createdBy and modifiedBy fields are set to Mr. Auditor")
    void create() {
        var createdUser = repository.save(new User().name("Rashidi Zin").username("rashidi"));

        assertThat(createdUser).extracting("created", "modified").isNotNull();
        assertThat(createdUser).extracting("createdBy", "modifiedBy").containsOnly("Mr. Auditor");
    }

}

Next we will verify that the modified field are updated when we update the User:

@Testcontainers
@DataMongoTest(includeFilters = @Filter(type = ANNOTATION, classes = EnableMongoAuditing.class))
class UserAuditTests {

    @Container
    @ServiceConnection
    private final static MongoDBContainer mongo = new MongoDBContainer("mongo:latest");

    @Autowired
    private UserRepository repository;

    @Test
    @DisplayName("When a user is updated Then modified field should be updated")
    void update() {
        var createdUser = repository.save(new User().name("Rashidi Zin").username("rashidi"));

        await().atMost(ofSeconds(1)).untilAsserted(() -> {
            var persistedUser = repository.findById(createdUser.id()).orElseThrow();
            var modifiedUser = repository.save(persistedUser.username("rashidi.zin"));

            assertThat(modifiedUser.modified()).isAfter(createdUser.modified());
        });
    }

}

Full implementation can be found in UserAuditTests.