Search code examples
javaspringmongodbkotlinmongodb-update

Spring Data MongoDB - how to update using @Update without setting most fields to null?


After reading Spring's docs at https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongodb.repositories.queries.update , I wrote this Repository method:

@Repository
interface TokenRepo: MongoRepository<TokenModel, String> {

    @Query("{ authorizationState: ?0 }")
    @Update("{ authorizationState: ?0, authorizationCode: ?1 }")
    fun updateCode(state: String, code: String): Int

}

Then I use it like this:

    @Test fun testUpdate() {
        val token = TestTokenModels().makeToken()
        val tokenSaved = tokenRepo.save(token)
        assertThat(tokenSaved).isNotNull.isEqualTo(token)
        assertThat(tokenSaved.requestTimestampMs).isNotNull()
        assertThat(tokenRepo.findByState(token.authorizationState)).isNotNull.isEqualTo(token)

        tokenRepo.updateCode(token.authorizationState, "someCode")
        val tokenUpdated = tokenRepo.findByState(token.authorizationState)  // FAILS!
        assertThat(tokenUpdated).isNotNull
        assertThat(tokenUpdated!!.authorizationCode).isNotNull.isEqualTo("someCode")
    }

But this fails when reading back from the database, because almost all fields were set to null:

org.springframework.data.mapping.model.MappingInstantiationException: 
Failed to instantiate com.tracker.bl.token.TokenModel using constructor 
fun `<init>`(kotlin.String, com.tracker.bl.token.TokenModel.Status, kotlin.String, kotlin.String, kotlin.String, kotlin.Long, kotlin.String, kotlin.String, kotlin.String?, kotlin.String?, com.tracker.rest.Oauth2TokenType, kotlin.String?, kotlin.String?, kotlin.Long?, java.time.ZonedDateTime, kotlin.String?): com.tracker.bl.token.TokenModel with arguments 637e4686ae781b603ac77c12,null,null,null,null,null,null,tokenFlowStateVC8g80BT,null,null,null,null,null,null,null,null,65026,null

    at org.springframework.data.mapping.model.
    KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter
    .createInstance(KotlinClassGeneratingEntityInstantiator.java:215)

How am I supposed to use @Update? Or is it only intended for things like $inc and $push? The docs is actually quite brief on this topic. I'm relatively new to MongoDB.


Solution

  • All right that was quick. It was me being new into MongoDB.

    Spring Data MongoDB is really just a thin layer, so one needs to follow the MongoDB query language to the extent where update happens through $set { ... }.

    So the method is supposed to be like this:

        @Query("{ authorizationState: ?0 }")
        @Update("{ '\$set': { authorizationCode: ?1 } }")
        fun updateCode(state: String, code: String): Int