Document Data Format: Data Classes
On this page
Overview
In this guide, you can learn how to store and retrieve data in the MongoDB Kotlin Driver using Kotlin data classes.
Serialize and Deserialize a Data Class
The driver natively supports encoding and decoding Kotlin data classes for MongoDB read and write operations using the default codec registry. The default codec registry is a collection of classes called codecs that define how to encode and decode Kotlin and Java types.
Example Data Class
The code examples in this section reference the following sample data class, which describes a data storage device:
data class DataStorage(val productName: String, val capacity: Double)
Insert a Data Class
You can insert a DataStorage
instance as shown in the following code:
val collection = database.getCollection<DataStorage>("data_storage") val record = DataStorage("tape", 5.0) collection.insertOne(record)
Retrieve a Data Class
You can retrieve documents as DataStorage
instances and print them
as shown in the following code:
val collection = database.getCollection<DataStorage>("data_storage_devices") // Retrieve and print the documents as data classes val resultsFlow = collection.find() resultsFlow.collect { println(it) }
DataStorage(productName=tape, capacity=5.0)
You specify a class for documents returned from a collection, even if it is different than the class you specified when retrieving the collection.
The following example performs an update to the document
represented by the DataStorage
data class in the previous example
and returns the updated document as a NewDataStorage
type. The
operation adds the releaseDate
field to the document with a
name
value of tape
:
// Define a data class for returned documents data class NewDataStorage( val productName: String, val capacity: Double, val releaseDate: LocalDate ) val filter = Filters.eq(DataStorage::productName.name, "tape") val update = Updates.currentDate("releaseDate") val options = FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER) // Specify the class for returned documents as the type parameter in withDocumentClass() val result = collection .withDocumentClass<NewDataStorage>() .findOneAndUpdate(filter, update, options) println("Updated document: ${result}")
Updated document: NewDataStorage(productName=tape, capacity=5.0, releaseDate=2023-06-15)
For more information about this feature, see Specify Return Type in the Databases and Collections guide.
Specify Component Conversion Using Annotations
This section describes the annotations you can use to configure the serialization behavior of data classes and provides an example to demonstrate the annotation behavior.
You can use the following annotations on data classes:
Annotation Name | Description |
---|---|
BsonId | Marks a property to serialize as the _id property. |
BsonProperty | Specifies a custom document field name when converting the data class
field to BSON. |
BsonRepresentation | Specifies the BSON type MongoDB uses to store the value. Use this annotation only when you need to store a value as a different BSON type than the data class property. WARNING: Your code might throw an exception if you include the
|
For reference information on these property annotations, refer to the org.bson.codecs.pojo.annotations package.
Example Annotated Data Class
The code examples in this section reference the following sample data class, which describes a network device:
data class NetworkDevice( val deviceId: String, val name: String, val deviceType: String )
Insert an Annotated Data Class
You can insert a NetworkDevice
instance as shown in the following code:
val collection = database.getCollection<NetworkDevice>("network_devices") // Insert the record val deviceId = ObjectId().toHexString() val device = NetworkDevice(deviceId, "Enterprise Wi-fi", "router") collection.insertOne(device)
The inserted document in MongoDB should resemble the following:
{ _id: ObjectId("fedc..."), name: 'Enterprise Wi-fi', type: 'router' }
Retrieve an Annotated Data Class
You can retrieve documents as NetworkDevice
instances and print them
as shown in the following code:
val collection = database.getCollection<NetworkDevice>("network_devices") // Return all documents in the collection as data classes val resultsFlow = collection.find() resultsFlow.collect { println(it) }
NetworkDevice(deviceId=645cf..., name=Enterprise Wi-fi, deviceType=router)
Operations with Recursive Types
The driver natively supports encoding and decoding of recursively defined data classes without causing runtime recursion. This support extends to cycles of multiple data class types in type definitions. The following code provides an example of a recursive data class design:
data class DataClassTree( val content: String, val left: DataClassTree?, val right: DataClassTree? )
You can perform read and write operations on recursively defined data classes the same
way you would for other data classes. The following code shows how you can
execute a find operation on a collection of DataClassTree
types:
val collection = database.getCollection<DataClassTree>("myCollection") val filter = Filters.eq("left.left.right.content", "high german") val resultsFlow = collection.find(filter) resultsFlow.collect { println(it) }
DataClassTree(content=indo-european, left=DataClassTree(content=germanic, left=DataClassTree(content=german, left=null, right=DataClassTree(content=high german, ...)), right=...)