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 Sync Driver by 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 by 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 result = collection.find().firstOrNull() println("${result}")
DataStorage(productName=tape, capacity=5.0)
Tip
Builder Methods and Data Class Properties
You can use the methods from builder classes directly with data class properties by adding the optional Kotlin Sync driver extensions dependency to your application. To learn more and view examples, see the Use Builders with Data Classes guide.
You must 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 DataStorageAlt
type. The
operation adds the releaseDate
field to the document in which the
value of the name
field is tape
:
// Define a data class for returned documents data class DataStorageAlt( 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 val newResult = collection .withDocumentClass<DataStorageAlt>() .findOneAndUpdate(filter, update, options) println("Document after update:\n${newResult}")
Document after update: DataStorageAlt(productName=tape, capacity=5.0, releaseDate=2025-01-24)
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 |
---|---|
| Marks a property to serialize as the |
| Specifies a custom document field name when converting the data class field to BSON. |
| Specifies the BSON type MongoDB uses to store the value. Use this annotation only when you must store a value as a different BSON type than the data class property. WARNING: Your code might throw an exception if you include the
|
To learn more these property annotations, see to the org.bson.codecs.pojo.annotations Package API documentation.
Annotated Data Class Example
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 ntwkColl = database.getCollection<NetworkDevice>("network_devices") val deviceId = ObjectId().toHexString() val device = NetworkDevice(deviceId, "Enterprise Wi-fi", "router") ntwkColl.insertOne(device)
The inserted document in MongoDB resembles the following:
{ "_id": {...}, "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 annotatedClassResult = ntwkColl.find().toList() println(annotatedClassResult)
[NetworkDevice(deviceId=..., 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 that you do for other data classes. The following
code shows how you can execute a find operation on a collection of
DataClassTree
types:
val treeColl = database.getCollection<DataClassTree>("language_trees") val treeFilter = Filters.eq("left.left.right.content", "high german") val treeResult = treeColl.find(treeFilter).firstOrNull() println(treeResult)
DataClassTree(content=indo-european, left=DataClassTree(content=germanic, left=DataClassTree(...)), right=DataClassTree(content=romance, ...))