springmongodbkotlinspring-data-mongodb

Type Mapping - Spring Data MongoDB


We have the use case that we’re storing deeply nested objects in MongoDB. Certain fields in this object can have different types. For instance let’s say an object can have a field that’s a collection of InterfaceType and there are different implementations of that say: ConcreteTypeA, ConcreteTypeB with different fields.

package foo.bar

sealed interface InterfaceType
data class ConcreteTypeA(val aField1: String, val aField2: Int) : InterfaceType
data class ConcreteTypeB(val bField: List<String>) : InterfaceType

When using Spring Data Mongo DB to persist say:

package bar.foo

@Document("myCollection")
data class MyDocument(
    @Id id: String,
    val value: InterfaceType
)

Spring will automatically add fields called _class that helps to instantiate the correct class on read. See also: Type Mapping :: Spring Data MongoDB

{
  "value" : {
    "aField1" : "some value",
    "aField2" : 1234,
    "_class" : "foo.bar.ConcreteTypeA"
  },
  "_class" : "bar.foo.MyDocument"
}

This all works fine, but of course this is not very refactoring safe… renaming the class or moving it to a different package will fail when reading the document. We could use @TypeAlias and register the aliased classes in the config, that would allow renaming/moving the class (as long as we don't touch the constant value in the annotation). Or alternatively have Document classes with lots of nullable fields and handle everything in the Repository.

What’s the recommended approach to handle this type of data structure in MongoDB/Spring?

Same question exists in MongoDB Community Forum


Solution

  • Thank you AndrewL and qsi for your inputs. We decided to take the @TypeAlias route.

    We also added a test using ArchUnit that ensures that classes that implement an interface and are used within a @Document annotated class are annotated with @TypeAlias.

    It's not highly sophisticated, but while it wouldn't be an issue for us to migrate the database and fix the fully qualified class names in _class, we're more afraid of accidentally missing these changes and then run into runtime issues.