Skip to content

Commit 8ebf256

Browse files
authored
DOCSP-30063: specify return type using withDocument (#91)
# Pull Request Info [PR Reviewing Guidelines](https://github.com/mongodb/docs-java/blob/master/REVIEWING.md) JIRA - https://jira.mongodb.org/browse/DOCSP-30063 Staging: - [Specify return type in DB/coll page](https://docs-mongodbcom-staging.corp.mongodb.com/kotlin/docsworker-xlarge/DOCSP-30063-withDocument-method/fundamentals/databases-collections/#specify-return-type) - [new content in data class doc format pg](https://docs-mongodbcom-staging.corp.mongodb.com/kotlin/docsworker-xlarge/DOCSP-30063-withDocument-method/fundamentals/data-formats/document-data-format-data-class/#retrieve-a-data-class) ## Self-Review Checklist - [x] Is this free of any warnings or errors in the RST? - [ ] Did you run a spell-check? - [ ] Did you run a grammar-check? - [x] Are all the links working?
1 parent daeac1d commit 8ebf256

7 files changed

+206
-26
lines changed

examples/src/test/kotlin/DataClassTest.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11

22
import com.mongodb.client.model.Filters
3+
import com.mongodb.client.model.FindOneAndUpdateOptions
4+
import com.mongodb.client.model.ReturnDocument
5+
import com.mongodb.client.model.Updates
36
import com.mongodb.kotlin.client.coroutine.MongoClient
47
import config.getConfig
58
import kotlinx.coroutines.flow.count
@@ -14,6 +17,7 @@ import org.junit.jupiter.api.AfterAll
1417
import org.junit.jupiter.api.AfterEach
1518
import org.junit.jupiter.api.Assertions.*
1619
import org.junit.jupiter.api.TestInstance
20+
import java.time.LocalDate
1721
import java.util.*
1822
import kotlin.test.*
1923

@@ -71,6 +75,26 @@ internal class DataClassTest {
7175
resultsFlow.collect { println(it) }
7276
// :snippet-end:
7377
assertEquals(tape, resultsFlow.firstOrNull())
78+
79+
// :snippet-start: retrieve-diff-data-class
80+
// Define a data class for returned documents
81+
data class NewDataStorage(
82+
val productName: String,
83+
val capacity: Double,
84+
val releaseDate: LocalDate
85+
)
86+
87+
val filter = Filters.eq(DataStorage::productName.name, "tape")
88+
val update = Updates.currentDate("releaseDate")
89+
val options = FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
90+
91+
// Specify the class for returned documents as the type parameter in withDocumentClass()
92+
val result = collection
93+
.withDocumentClass<NewDataStorage>()
94+
.findOneAndUpdate(filter, update, options)
95+
96+
println("Updated document: ${result}")
97+
// :snippet-end:
7498
}
7599

76100
// :snippet-start: annotated-data-class

examples/src/test/kotlin/DatabaseCollectionsTest.kt

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11

2-
import com.mongodb.client.model.CreateCollectionOptions
3-
import com.mongodb.client.model.Filters
4-
import com.mongodb.client.model.ValidationOptions
2+
import com.mongodb.client.model.*
53
import com.mongodb.kotlin.client.coroutine.MongoClient
64
import config.getConfig
75
import kotlinx.coroutines.flow.toList
86
import kotlinx.coroutines.runBlocking
97
import org.bson.codecs.pojo.annotations.BsonId
108
import org.bson.types.ObjectId
119
import org.junit.jupiter.api.AfterAll
10+
import org.junit.jupiter.api.Assertions
1211
import org.junit.jupiter.api.Test
1312
import org.junit.jupiter.api.TestInstance
1413
import kotlin.test.assertTrue
1514

16-
1715
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
1816
internal class DatabaseCollectionsTest {
1917
// :snippet-start: test-data-class
@@ -86,4 +84,48 @@ internal class DatabaseCollectionsTest {
8684
val collectionList = database.listCollectionNames().toList()
8785
assertTrue(collectionList.contains("movies"))
8886
}
87+
88+
// :snippet-start: fruit-data-class
89+
data class Fruit(
90+
@BsonId val id: Int,
91+
val name: String,
92+
val qty: Int,
93+
val seasons: List<String>
94+
)
95+
// :snippet-end:
96+
97+
@Test
98+
fun returnTypeTest() = runBlocking {
99+
database.createCollection("fruits")
100+
// :snippet-start: return-type
101+
val collection =
102+
database.getCollection<Fruit>("fruits")
103+
collection.insertOne(Fruit(1, "strawberry", 205, listOf("summer"))) // :remove:
104+
105+
// Define a data class for returned documents
106+
data class NewFruit(
107+
@BsonId val id: Int,
108+
val name: String,
109+
val quantity: Int,
110+
val seasons: List<String>
111+
)
112+
113+
val filter = Filters.eq(Fruit::name.name, "strawberry")
114+
val update = Updates.combine(
115+
Updates.rename(Fruit::qty.name, "quantity"),
116+
Updates.push(Fruit::seasons.name, "fall"),
117+
)
118+
val options = FindOneAndUpdateOptions()
119+
.returnDocument(ReturnDocument.AFTER)
120+
121+
// Specify the class for returned documents as the type parameter in withDocumentClass()
122+
val result = collection
123+
.withDocumentClass<NewFruit>()
124+
.findOneAndUpdate(filter, update, options)
125+
println(result)
126+
// :snippet-end:
127+
128+
// Junit test for the above code
129+
Assertions.assertEquals(NewFruit(1,"strawberry", 205, listOf("summer", "fall")), result)
130+
}
89131
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Define a data class for returned documents
2+
data class NewDataStorage(
3+
val productName: String,
4+
val capacity: Double,
5+
val releaseDate: LocalDate
6+
)
7+
8+
val filter = Filters.eq(DataStorage::productName.name, "tape")
9+
val update = Updates.currentDate("releaseDate")
10+
val options = FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
11+
12+
// Specify the class for returned documents as the type parameter in withDocumentClass()
13+
val result = collection
14+
.withDocumentClass<NewDataStorage>()
15+
.findOneAndUpdate(filter, update, options)
16+
17+
println("Updated document: ${result}")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
data class Fruit(
2+
@BsonId val id: Int,
3+
val name: String,
4+
val qty: Int,
5+
val seasons: List<String>
6+
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
val collection =
2+
database.getCollection<Fruit>("fruits")
3+
4+
// Define a data class for returned documents
5+
data class NewFruit(
6+
@BsonId val id: Int,
7+
val name: String,
8+
val quantity: Int,
9+
val seasons: List<String>
10+
)
11+
12+
val filter = Filters.eq(Fruit::name.name, "strawberry")
13+
val update = Updates.combine(
14+
Updates.rename(Fruit::qty.name, "quantity"),
15+
Updates.push(Fruit::seasons.name, "fall"),
16+
)
17+
val options = FindOneAndUpdateOptions()
18+
.returnDocument(ReturnDocument.AFTER)
19+
20+
// Specify the class for returned documents as the type parameter in withDocumentClass()
21+
val result = collection
22+
.withDocumentClass<NewFruit>()
23+
.findOneAndUpdate(filter, update, options)
24+
println(result)

source/fundamentals/data-formats/document-data-format-data-class.txt

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
Document Data Format: Data Classes
55
==================================
66

7-
.. default-domain:: mongodb
8-
97
.. contents:: On this page
108
:local:
119
:backlinks: none
@@ -62,6 +60,31 @@ as shown in the following code:
6260

6361
DataStorage(productName=tape, capacity=5.0)
6462

63+
You specify a class for documents returned from a collection, even if it
64+
is different than the class you specified when retrieving the
65+
collection.
66+
67+
The following example performs an update to the document
68+
represented by the ``DataStorage`` data class in the previous example
69+
and returns the updated document as a ``NewDataStorage`` type. The
70+
operation adds the ``releaseDate`` field to the document with a
71+
``name`` value of ``tape``:
72+
73+
.. io-code-block::
74+
:copyable: true
75+
76+
.. input:: /examples/generated/DataClassTest.snippet.retrieve-diff-data-class.kt
77+
:language: kotlin
78+
:emphasize-lines: 2-6,13-15
79+
80+
.. output::
81+
:language: console
82+
83+
Updated document: NewDataStorage(productName=tape, capacity=5.0, releaseDate=2023-06-15)
84+
85+
For more information about this feature, see :ref:`Specify Return Type
86+
<db-coll-specify-return-type>` in the Databases and Collections guide.
87+
6588
.. _fundamentals-data-class-annotations:
6689

6790
Specify Component Conversion Using Annotations

source/fundamentals/databases-collections.txt

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
Databases and Collections
33
=========================
44

5-
.. default-domain:: mongodb
6-
75
.. contents:: On this page
86
:local:
97
:backlinks: none
@@ -14,23 +12,25 @@ Overview
1412
--------
1513

1614
In this guide, you can learn how to use MongoDB databases and
17-
collections with the MongoDB Kotlin driver.
15+
collections with the MongoDB Kotlin driver.
1816

1917
MongoDB organizes data into a hierarchy of the following levels:
2018

2119
#. **Databases**: Databases are the top level of data organization in a MongoDB instance.
2220

2321
#. **Collections**: Databases are organized into collections which contain **documents**.
2422

25-
#. **Documents**: Documents contain literal data such as strings, numbers, and dates, as well as other embedded documents. For more information on document field types and structure, see the :manual:`server documentation for documents </core/document/>`.
23+
#. **Documents**: Documents contain literal data such as strings, numbers, and dates, as well as other embedded documents. For more information on document field types and structure, see the :manual:`Server documentation on documents </core/document/>`.
2624

27-
With the MongoDB Kotlin driver, data can be modeled using Kotlin data classes or you can use a
28-
`Document <{+api+}/apidocs/bson/org/bson/Document.html>`__ class
29-
to store and retrieve data from MongoDB.
25+
With the MongoDB Kotlin driver, you can model data by using Kotlin data
26+
classes or by using the `Document
27+
<{+api+}/apidocs/bson/org/bson/Document.html>`__ class to store and
28+
retrieve data from MongoDB.
3029

31-
.. TODO:(DOCSP-29224): add back in when document data format data classes are documented
32-
.. To learn more about using data classes to store and retrieve data, refer to
33-
.. :ref:`Document Data Format: Data Classes <fundamentals-data-classes>`.
30+
To learn more about using data classes, see
31+
the guide on the :ref:`Data Class Data Format
32+
<fundamentals-data-classes>`. To learn more about using the ``Document``
33+
class, see the guide on the :ref:`Document Data Format <kotlin-document-format>`.
3434

3535
Access a Database
3636
-----------------
@@ -40,7 +40,7 @@ Use the `getDatabase()
4040
a ``MongoClient`` instance to access a ``MongoDatabase`` in a MongoDB
4141
instance.
4242

43-
The following example accesses a database named "testDatabase":
43+
The following example accesses a database named ``testDatabase``:
4444

4545
.. literalinclude:: /examples/generated/DatabaseCollectionsTest.snippet.access-database.kt
4646
:language: kotlin
@@ -53,7 +53,7 @@ Use the `getCollection()
5353
method of a ``MongoDatabase`` instance to access a
5454
``MongoCollection`` in a database of your connected MongoDB instance.
5555

56-
The following example accesses a collection named "testCollection" from a
56+
The following example accesses a collection named ``testCollection`` from a
5757
``MongoDatabase`` that contains documents of type ``ExampleDataClass``:
5858

5959
.. literalinclude:: /examples/generated/DatabaseCollectionsTest.snippet.test-data-class.kt
@@ -69,6 +69,48 @@ The following example accesses a collection named "testCollection" from a
6969
MongoDB implicitly creates the collection when you first insert data
7070
into that collection.
7171

72+
.. _db-coll-specify-return-type:
73+
74+
Specify Return Type
75+
~~~~~~~~~~~~~~~~~~~
76+
77+
The driver provides a way for you to specify a class for documents
78+
returned from a collection, even if it is different than the class you
79+
specified when retrieving the collection. You can specify a return class
80+
by using the `MongoCollection.withDocumentClass()
81+
<{+api-kotlin+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-collection/with-document-class.html>`__
82+
method.
83+
84+
Specifying a different return class could be useful in the following
85+
situations:
86+
87+
- Your collection contains multiple data types.
88+
- You specify a projection that changes your data fields.
89+
- You cannot directly specify a return type on a method that changes the data,
90+
such as ``findOneAndUpdate()`` or ``findOneAndReplace()``.
91+
92+
The following example retrieves a collection that
93+
contains data represented by the ``Fruit`` data class but returns the result
94+
of a ``findOneAndUpdate()`` operation as an instance of the ``NewFruit``
95+
class. The operation changes the name of the ``qty`` field to
96+
``quantity`` and adds an item to the ``seasons`` array field in the
97+
document with a ``name`` value of ``"strawberry"``:
98+
99+
.. literalinclude:: /examples/generated/DatabaseCollectionsTest.snippet.fruit-data-class.kt
100+
:language: kotlin
101+
:caption: Fruit data model
102+
103+
.. io-code-block::
104+
105+
.. input:: /examples/generated/DatabaseCollectionsTest.snippet.return-type.kt
106+
:language: kotlin
107+
:emphasize-lines: 5-10,21-23
108+
109+
.. output::
110+
:language: console
111+
112+
NewFruit(id=1, name=strawberry, quantity=205, seasons=[summer, fall])
113+
72114
Create a Collection
73115
-------------------
74116

@@ -77,7 +119,7 @@ Use the `createCollection()
77119
method of a ``MongoDatabase`` instance to create a collection
78120
in a database of your connected MongoDB instance.
79121

80-
The following example creates a collection called "exampleCollection":
122+
The following example creates a collection called ``exampleCollection``:
81123

82124
.. literalinclude:: /examples/generated/DatabaseCollectionsTest.snippet.create-collection.kt
83125
:language: kotlin
@@ -96,15 +138,15 @@ against a series of filters during writes to a collection. You can
96138
specify these filters using the `ValidationOptions
97139
<{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/ValidationOptions.html>`__
98140
class, which accepts a series of `Filters
99-
<{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Filters.html>`__
100-
that specifies the validation rules and expressions:
141+
<{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Filters.html>`__ instances
142+
that specify the validation rules and expressions:
101143

102144
.. literalinclude:: /examples/generated/DatabaseCollectionsTest.snippet.validation.kt
103145
:language: kotlin
104146

105147
For more information, see the server documentation for :manual:`document
106148
validation </core/document-validation>`.
107-
149+
108150
Get a List of Collections
109151
-------------------------
110152

@@ -179,7 +221,9 @@ normally inherit:
179221
the method is called retains its original preference and concern
180222
settings.
181223

182-
For more information, see the server documentation on
183-
:manual:`read preferences </core/read-preference/>`,
184-
:manual:`read concerns </reference/read-concern/>`, and
185-
:manual:`write concerns </reference/write-concern/>`.
224+
For more information on these topics, see the following pages in the
225+
Server manual:
226+
227+
- :manual:`Read Preference </core/read-preference/>`
228+
- :manual:`Read Concern </reference/read-concern/>`
229+
- :manual:`Write Concern </reference/write-concern/>`

0 commit comments

Comments
 (0)