diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 42a97b1b..5338cdab 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,9 @@ # Pull Request Info -[PR Reviewing Guidelines](https://github.com/mongodb/docs-java/blob/master/REVIEWING.md) +[PR Reviewing Guidelines](https://github.com/mongodb/docs-kotlin/blob/master/REVIEWING.md) -JIRA - https://jira.mongodb.org/browse/DOCSP-NNNNN -Staging - https://docs-mongodbcom-staging.corp.mongodb.com/drivers/docsworker-xlarge/NNNNN/ +JIRA - +Staging - ## Self-Review Checklist @@ -11,3 +11,4 @@ Staging - https://docs-mongodbcom-staging.corp.mongodb.com/drivers/docsworker-xl - [ ] Did you run a spell-check? - [ ] Did you run a grammar-check? - [ ] Are all the links working? +- [ ] Are the [facets and meta keywords](https://wiki.corp.mongodb.com/display/DE/Docs+Taxonomy) accurate? diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 93643a0b..424bc68a 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -18,7 +18,7 @@ repositories { dependencies { implementation("org.mongodb:mongodb-driver-kotlin-coroutine:$kotlin_mongodb_version") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1") - testImplementation(kotlin("test")) + testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.10") implementation("org.slf4j:slf4j-api:2.0.5") implementation("ch.qos.logback:logback-classic:1.4.7") implementation("io.github.cdimascio:dotenv-kotlin:6.4.1") @@ -29,6 +29,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") implementation("org.mongodb:bson-kotlinx:4.10.0-alpha1") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") } tasks.test { diff --git a/examples/gradle.properties b/examples/gradle.properties index 800fd287..83ff08dc 100644 --- a/examples/gradle.properties +++ b/examples/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style=official -kotlin_mongodb_version=4.10.0 +kotlin_mongodb_version=4.11.0 diff --git a/examples/src/test/kotlin/AggregatesBuilderTest.kt b/examples/src/test/kotlin/AggregatesBuilderTest.kt index 85f29196..7baabe05 100644 --- a/examples/src/test/kotlin/AggregatesBuilderTest.kt +++ b/examples/src/test/kotlin/AggregatesBuilderTest.kt @@ -28,6 +28,7 @@ import com.mongodb.client.model.geojson.Position import com.mongodb.client.model.search.SearchOperator import com.mongodb.client.model.search.SearchOptions import com.mongodb.client.model.search.SearchPath +import com.mongodb.client.model.search.VectorSearchOptions.vectorSearchOptions import com.mongodb.kotlin.client.coroutine.MongoClient import config.getConfig import kotlinx.coroutines.flow.firstOrNull @@ -80,6 +81,15 @@ class AggregatesBuilderTest { ) // :snippet-end: + // :snippet-start: vector-search-data-class + data class MovieAlt( + val title: String, + val year: Int, + val plot: String, + val plotEmbedding: List + ) + // :snippet-end: + companion object { val config = getConfig() private val client = MongoClient.create(config.connectionUri) @@ -674,7 +684,15 @@ class AggregatesBuilderTest { // :snippet-end: Aggregates.sort(Sorts.descending(Results::count.name, "_id")))) val results = resultsFlow.toList() - val actual = listOf(Results("Drama", 8), Results("Crime", 3), Results("Action", 2), Results("Thriller", 1), Results("Sci-Fi", 1), Results("Romance", 1), Results("Mystery", 1),) + val actual = listOf( + Results("Drama", 8), + Results("Crime", 3), + Results("Action", 2), + Results("Thriller", 1), + Results("Sci-Fi", 1), + Results("Romance", 1), + Results("Mystery", 1) + ) assertEquals(results, actual) } @@ -951,4 +969,27 @@ class AggregatesBuilderTest { assertEquals(1, resultsFlow.toList().size) assertEquals(1, results.first().get("count", Document::class.java).get("lowerBound", java.lang.Long::class.java)?.toInt()) } + + /* NOTE: Test is not run by default. Vector search requires the creation of a vector search index on the collection before running. + */ + @Ignore + fun vectorSearchTest() = runBlocking { + val resultsFlow = movieCollection.aggregate( + listOf( + // :snippet-start: vector-search + Aggregates.vectorSearch( + SearchPath.fieldPath(MovieAlt::plotEmbedding.name), + listOf(-0.0072121937, -0.030757688, -0.012945653), + "mflix_movies_embedding_index", + 2.toLong(), + 1.toLong(), + vectorSearchOptions().filter(Filters.gte(MovieAlt::year.name, 2016)) + ) + // :snippet-end: + ) + ) + val results = resultsFlow.toList() + assertEquals(1, resultsFlow.toList().size) + assertEquals(1, results.first().get("count", Document::class.java).get("lowerBound", java.lang.Long::class.java)?.toInt()) + } } \ No newline at end of file diff --git a/examples/src/test/kotlin/ChangeStreamsTest.kt b/examples/src/test/kotlin/ChangeStreamsTest.kt index 7086f7c2..710eb0ed 100644 --- a/examples/src/test/kotlin/ChangeStreamsTest.kt +++ b/examples/src/test/kotlin/ChangeStreamsTest.kt @@ -13,6 +13,7 @@ import config.getConfig import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.bson.BsonDocument import org.bson.Document import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.AfterEach @@ -136,6 +137,37 @@ internal class ChangeStreamsTest { } + // Ignore annotation added because this test requires a MongoDB 7.0 deployment + @Ignore + fun splitLargeChangeStreamTest() = runBlocking { + val changeEvents = mutableListOf>() + // :snippet-start: split-large-change-stream + val pipeline = listOf(BsonDocument().append("\$changeStreamSplitLargeEvent", BsonDocument())) + + val job = launch { + val changeStream = collection.watch(pipeline) + changeStream.collect { + println("Received a change event: $it") + changeEvents.add(it) // :remove: + } + } + // :snippet-end: + + // Perform MongoDB operations that trigger change events... + delay(1) + val testData = Document("city", "Rio de Janeiro") + collection.insertOne(testData) + + // Wait for change events + delay(1000) + + // Cancel the change stream when you're done listening for events. + job.cancel() + + // Change stream only captures the insert event, not the delete event. + assertEquals(1, changeEvents.size) + } + // NOTE: Test is being ignored because it will not work with a shared M0 cluster. // Must have a local cluster with a replica set or >=M10 on Atlas to successfully run. @Ignore diff --git a/examples/src/test/kotlin/InsertTest.kt b/examples/src/test/kotlin/InsertTest.kt index 77761244..221db750 100644 --- a/examples/src/test/kotlin/InsertTest.kt +++ b/examples/src/test/kotlin/InsertTest.kt @@ -1,5 +1,3 @@ - - import com.mongodb.MongoBulkWriteException import com.mongodb.kotlin.client.coroutine.MongoClient import config.getConfig diff --git a/examples/src/test/kotlin/KotlinXSerializationTest.kt b/examples/src/test/kotlin/KotlinXSerializationTest.kt index 132adab4..bd08de64 100644 --- a/examples/src/test/kotlin/KotlinXSerializationTest.kt +++ b/examples/src/test/kotlin/KotlinXSerializationTest.kt @@ -1,4 +1,5 @@ +import com.mongodb.client.model.Filters.eq import com.mongodb.kotlin.client.coroutine.MongoClient import config.getConfig import kotlinx.coroutines.flow.first @@ -8,11 +9,22 @@ import kotlinx.serialization.Contextual import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.datetime.* +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToJsonElement +import org.bson.BsonDateTime import org.bson.Document import org.bson.codecs.configuration.CodecRegistries import org.bson.codecs.kotlinx.BsonConfiguration +import org.bson.codecs.kotlinx.BsonDecoder +import org.bson.codecs.kotlinx.BsonEncoder import org.bson.codecs.kotlinx.KotlinSerializerCodec import org.bson.codecs.kotlinx.ObjectIdSerializer import org.bson.types.ObjectId @@ -22,6 +34,7 @@ import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance +import java.util.Date @TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class KotlinXSerializationTest { @@ -118,5 +131,52 @@ internal class KotlinXSerializationTest { collection.drop() } + // :snippet-start: kserializer + object InstantAsBsonDateTime : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("InstantAsBsonDateTime", PrimitiveKind.LONG) + + override fun serialize(encoder: Encoder, value: Instant) { + when (encoder) { + is BsonEncoder -> encoder.encodeBsonValue(BsonDateTime(value.toEpochMilliseconds())) + else -> throw SerializationException("Instant is not supported by ${encoder::class}") + } + } + + override fun deserialize(decoder: Decoder): Instant { + return when (decoder) { + is BsonDecoder -> Instant.fromEpochMilliseconds(decoder.decodeBsonValue().asDateTime().value) + else -> throw SerializationException("Instant is not supported by ${decoder::class}") + } + } + } + // :snippet-end: + + @Test + fun customKSerializerTest() = runBlocking { + // :snippet-start: kserializer-dataclass + @Serializable + data class PaintOrder( + val color: String, + val qty: Int, + @Serializable(with = InstantAsBsonDateTime::class) + val orderDate: Instant, + ) + // :snippet-end: + + val collection = database.getCollection("orders") + val paintOrder = PaintOrder("magenta", 5, Instant.parse("2024-01-15T00:00:00Z")) + val insertOneResult = collection.insertOne(paintOrder) + + val resultsFlow = collection.withDocumentClass() + .find(eq(PaintOrder::color.name, "magenta")) + .firstOrNull() + + if (resultsFlow != null) { + assertEquals(resultsFlow["orderDate"], Date.from(java.time.Instant.parse("2024-01-15T00:00:00Z"))) + } + + collection.drop() + } + } diff --git a/examples/src/test/kotlin/SearchIndexesTest.kt b/examples/src/test/kotlin/SearchIndexesTest.kt new file mode 100644 index 00000000..c7d4fcf3 --- /dev/null +++ b/examples/src/test/kotlin/SearchIndexesTest.kt @@ -0,0 +1,119 @@ + +import com.mongodb.client.model.SearchIndexModel +import com.mongodb.kotlin.client.coroutine.MongoClient +import config.getConfig +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.runBlocking +import org.bson.Document +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import kotlin.test.Ignore +import kotlin.test.assertFalse + +// :replace-start: { +// "terms": { +// "CONNECTION_URI_PLACEHOLDER": "\"\"" +// } +// } +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class SearchIndexesTest { + + companion object { + private val config = getConfig() + private val CONNECTION_URI_PLACEHOLDER = config.connectionUri + + val mongoClient = MongoClient.create(CONNECTION_URI_PLACEHOLDER) + val database = mongoClient.getDatabase("sample_mflix") + val moviesCollection = database.getCollection("movies") + + @AfterAll + @JvmStatic + fun afterAll() { + runBlocking { + moviesCollection.drop() + } + mongoClient.close() + } + } + + @Ignore + @Test + fun singleSearchIndexTest() = runBlocking { + // :snippet-start: single-search-index-create + val index = Document( + "mappings", + Document("dynamic", true) + ) + val resultCreateIndex = moviesCollection.createSearchIndex("myIndex", index) + // :snippet-end: + println("Index created: $resultCreateIndex") + assertEquals("myIndex", resultCreateIndex) + } + + @Ignore + @Test + fun multipleSearchIndexTest() = runBlocking { + // :snippet-start: multi-search-index-create + val indexOne = SearchIndexModel( + "myIndex1", + Document("analyzer", "lucene.standard").append( + "mappings", Document("dynamic", true) + ) + ) + + val indexTwo = SearchIndexModel( + "myIndex2", + Document("analyzer", "lucene.simple").append( + "mappings", Document("dynamic", true) + ) + ) + + val resultCreateIndexes = moviesCollection + .createSearchIndexes(listOf(indexOne, indexTwo)) + // :snippet-end: + assertEquals(listOf("myIndex1", "myIndex2"), resultCreateIndexes.toList()) + } + + @Ignore + @Test + fun listSearchIndexTest() = runBlocking { + // :snippet-start: list-search-indexes + val searchIndexesList = moviesCollection.listSearchIndexes().toList() + // :snippet-end: + + assertFalse(searchIndexesList.isEmpty()) + } + + @Ignore + @Test + fun updateSearchIndexTest() = runBlocking { + // :snippet-start: update-search-indexes + moviesCollection.updateSearchIndex( + "myIndex", + Document("analyzer", "lucene.simple").append( + "mappings", + Document("dynamic", false) + .append( + "fields", + Document( + "title", + Document("type", "string") + ) + ) + ) + ) + // :snippet-end: + } + + @Ignore + @Test + fun dropSearchIndexTest() = runBlocking { + // :snippet-start: drop-search-index + moviesCollection.dropSearchIndex("myIndex"); + // :snippet-end: + } + +} +// :replace-end: diff --git a/examples/src/test/kotlin/SocksTest.kt b/examples/src/test/kotlin/SocksTest.kt new file mode 100644 index 00000000..8eebaa17 --- /dev/null +++ b/examples/src/test/kotlin/SocksTest.kt @@ -0,0 +1,110 @@ +import com.mongodb.ConnectionString +import com.mongodb.MongoClientSettings +import com.mongodb.MongoException +import com.mongodb.kotlin.client.coroutine.MongoClient +import config.getConfig +import kotlinx.coroutines.runBlocking +import org.bson.BsonInt64 +import org.bson.Document +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.TestInstance +import kotlin.test.Ignore + +// :replace-start: { +// "terms": { +// "CONNECTION_URI_PLACEHOLDER": "\"\"", +// "${uri}&": "mongodb+srv://:@/?" +// } +// } + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +internal class SocksTest { + + /* NOTE: SOCKS5 tests are not run by default. To run these tests, + * you need access to proxy server credentials. + * Replace the placeholders in the test with your credentials, then replace + * the @Ignore annotation with @Test on the tests you want to run. + */ + + companion object { + private val config = getConfig() + val CONNECTION_URI_PLACEHOLDER = config.connectionUri + var higherScopedClient: MongoClient? = null + + @AfterAll + @JvmStatic + fun afterAll() { + runBlocking { + higherScopedClient?.close() + } + } + } + + @Ignore + fun mongoClientSettingsSocks() = runBlocking { + // :snippet-start: socks-mongoclientsettings + val uri = CONNECTION_URI_PLACEHOLDER + + val mongoClient = MongoClient.create( + MongoClientSettings.builder() + .applyConnectionString(ConnectionString(uri)) + .applyToSocketSettings{ builder -> + builder + .applyToProxySettings{ proxyBuilder -> + proxyBuilder + .host("") + .port("".toInt()) + .username("") + .password("") + .build() + } + } + .build() + ) + // :snippet-end: + lateinit var higherScopedCommandResult: Document + val database = mongoClient.getDatabase("admin") + try { + // Send a ping to confirm a successful connection + val command = Document("ping", BsonInt64(1)) + val commandResult = database.runCommand(command) + println("Pinged your deployment. You successfully connected to MongoDB!") + higherScopedCommandResult = commandResult + } catch (me: MongoException) { + System.err.println(me) + } + higherScopedClient = mongoClient + Assertions.assertEquals(1.0, higherScopedCommandResult["ok"].toString().toDouble()) + } + + @Ignore + fun connectionStringSocks() = runBlocking { + val uri = CONNECTION_URI_PLACEHOLDER + // :snippet-start: socks-connection-string + val connectionString = ConnectionString( + "${uri}&" + + "proxyHost=" + + "&proxyPort=" + + "&proxyUsername=" + + "&proxyPassword=" + ) + + val mongoClient = MongoClient.create(connectionString) + // :snippet-end: + lateinit var higherScopedCommandResult: Document + val database = mongoClient.getDatabase("admin") + try { + // Send a ping to confirm a successful connection + val command = Document("ping", BsonInt64(1)) + val commandResult = database.runCommand(command) + println("Pinged your deployment. You successfully connected to MongoDB!") + higherScopedCommandResult = commandResult + } catch (me: MongoException) { + System.err.println(me) + } + higherScopedClient = mongoClient + Assertions.assertEquals(1.0, higherScopedCommandResult["ok"].toString().toDouble()) + } +} +// :replace-end: \ No newline at end of file diff --git a/examples/src/test/kotlin/UpdatesBuildersTest.kt b/examples/src/test/kotlin/UpdatesBuildersTest.kt index e50123bb..15b16d05 100644 --- a/examples/src/test/kotlin/UpdatesBuildersTest.kt +++ b/examples/src/test/kotlin/UpdatesBuildersTest.kt @@ -24,9 +24,13 @@ class UpdatesBuildersTest { @BsonId val id: Int, val color: String, val qty: Int?, - val vendor: List?, + val vendor: List?, val lastModified: LocalDateTime? ) + + data class Vendor ( + val name: String, + ) // :snippet-end: companion object { @@ -51,7 +55,7 @@ class UpdatesBuildersTest { fun beforeEach() { runBlocking { val date = LocalDateTime.of(2000, 1, 1,7,0,0) // Jan 1, 2000, 7:00:00 - val redPaint = PaintOrder(1, "red", 5, listOf("A", "D", "M"), date) + val redPaint = PaintOrder(1, "red", 5, listOf(Vendor("A"), Vendor("D"), Vendor("M")), date) collection.insertOne(redPaint) } } @@ -193,10 +197,10 @@ class UpdatesBuildersTest { fun addToSetUpdateTest() = runBlocking { // :snippet-start: add-to-set-update val filter = Filters.eq("_id", 1) - val update = Updates.addToSet(PaintOrder::vendor.name, "C") + val update = Updates.addToSet(PaintOrder::vendor.name, Vendor("C")) collection.updateOne(filter, update) // :snippet-end: - assertEquals(listOf("A", "D", "M", "C"), getDocument().vendor) + assertEquals(listOf(Vendor("A"), Vendor("D"), Vendor("M"), Vendor("C")), getDocument().vendor) } @Test @@ -206,37 +210,37 @@ class UpdatesBuildersTest { val update = Updates.popFirst(PaintOrder::vendor.name) collection.updateOne(filter, update) // :snippet-end: - assertEquals(listOf("D", "M"), getDocument().vendor) + assertEquals(listOf(Vendor("D"), Vendor("M")), getDocument().vendor) } @Test fun pullAllUpdateTest() = runBlocking { // :snippet-start: pull-all-update val filter = Filters.eq("_id", 1) - val update = Updates.pullAll(PaintOrder::vendor.name, listOf("A", "M")) + val update = Updates.pullAll(PaintOrder::vendor.name, listOf(Vendor("A"), Vendor("M"))) collection.updateOne(filter, update) // :snippet-end: - assertEquals(listOf("D"), getDocument().vendor) + assertEquals(listOf(Vendor("D")), getDocument().vendor) } @Test fun pullUpdateTest() = runBlocking { // :snippet-start: pull-update val filter = Filters.eq("_id", 1) - val update = Updates.pull(PaintOrder::vendor.name, "D") + val update = Updates.pull(PaintOrder::vendor.name, Vendor("D")) collection.updateOne(filter, update) // :snippet-end: - assertEquals(listOf("A", "M"), getDocument().vendor) + assertEquals(listOf(Vendor("A"), Vendor("M")), getDocument().vendor) } @Test fun pushUpdateTest() = runBlocking { // :snippet-start: push-update val filter = Filters.eq("_id", 1) - val update = Updates.push(PaintOrder::vendor.name, "Q") + val update = Updates.push(PaintOrder::vendor.name, Vendor("Q")) collection.updateOne(filter, update) // :snippet-end: - assertEquals(listOf("A", "D", "M", "Q"), getDocument().vendor) + assertEquals(listOf(Vendor("A"), Vendor("D"), Vendor("M"), Vendor("Q")), getDocument().vendor) } @Test @@ -246,13 +250,13 @@ class UpdatesBuildersTest { val update = Updates.combine( Updates.set(PaintOrder::color.name, "purple"), Updates.inc(PaintOrder::qty.name, 6), - Updates.push(PaintOrder::vendor.name, "R") + Updates.push(PaintOrder::vendor.name, Vendor("R")) ) collection.updateOne(filter, update) // :snippet-end: val doc = getDocument() assertEquals("purple", doc.color) assertEquals(11, doc.qty) - assertEquals(listOf("A", "D", "M", "R"), doc.vendor) + assertEquals(listOf(Vendor("A"), Vendor("D"), Vendor("M"), Vendor("R")), doc.vendor) } } diff --git a/snooty.toml b/snooty.toml index 6d244ae1..c2ff2517 100644 --- a/snooty.toml +++ b/snooty.toml @@ -22,7 +22,7 @@ driver-long = "MongoDB Kotlin Driver" version = "4.11" full-version = "{+version+}.0" mdb-server = "MongoDB server" -kotlin-docs = "https://kotlinlang.org/docs" +kotlin-docs = "https://kotlinlang.org" package-name-org = "mongodb-org" api = "https://mongodb.github.io/mongo-java-driver/{+version+}" diff --git a/source/examples/ServerManualCodeExamples.kt b/source/examples/ServerManualCodeExamples.kt new file mode 100644 index 00000000..8802341d --- /dev/null +++ b/source/examples/ServerManualCodeExamples.kt @@ -0,0 +1,162 @@ +import com.mongodb.MongoException +import com.mongodb.client.model.Filters.* +import com.mongodb.kotlin.client.coroutine.MongoClient +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.runBlocking +import org.bson.Document + +fun main() = runBlocking { + val uri = "" + val mongoClient = MongoClient.create(uri) + val database = mongoClient.getDatabase("db") + val collection = database.getCollection("inventory") + + // Start Example 1 + val result = collection.insertOne( + Document("item", "canvas") + .append("qty", 100) + .append("tags", listOf("cotton")) + .append("size", Document("h", 28) + .append("w", 35.5) + .append("uom", "cm") + ) + ) + // End Example 1 + + println("Success! Inserted document: " + result.insertedId) + + // Start Example 2 + val flowInsertOne = collection.withDocumentClass() + .find(eq("item", "canvas")) + .firstOrNull() + // End Example 2 + + if (flowInsertOne == null) { + println("No results found."); + } else { + println(flowInsertOne) + } + + collection.deleteMany(empty()) + + // Start Example 3 + val results = collection.insertMany( + listOf( + Document("item", "journal") + .append("qty", 25) + .append("tags", listOf("blank", "red")) + .append("size", Document("h", 14) + .append("w", 21) + .append("uom", "cm") + ), + Document("item", "mat") + .append("qty", 25) + .append("tags", listOf("gray")) + .append("size", Document("h", 27.9) + .append("w", 35.5) + .append("uom", "cm") + ), + Document("item", "mousepad") + .append("qty", 25) + .append("tags", listOf("gel", "blue")) + .append("size", Document("h", 19) + .append("w", 22.85) + .append("uom", "cm") + ) + ) + ) + // End Example 3 + + println("Success! Inserted documents: " + results.insertedIds) + + // Start Example 7 + val flowInsertMany = collection.withDocumentClass() + .find(empty()) + // End Example 7 + + flowInsertMany.collect { println(it) } + collection.deleteMany(empty()) + + // Start Example 6 + collection.insertMany( + listOf( + Document("item", "journal") + .append("qty", 25) + .append("size", Document("h", 14) + .append("w", 21) + .append("uom", "cm") + ) + .append("status", "A"), + Document("item", "notebook") + .append("qty", 50) + .append("size", Document("h", 8.5) + .append("w", 11) + .append("uom", "in") + ) + .append("status", "A"), + Document("item", "paper") + .append("qty", 100) + .append("size", Document("h", 8.5) + .append("w", 11) + .append("uom", "in") + ) + .append("status", "D"), + Document("item", "planner") + .append("qty", 75) + .append("size", Document("h", 22.85) + .append("w", 30) + .append("uom", "cm") + ) + .append("status", "D"), + Document("item", "postcard") + .append("qty", 45) + .append("size", Document("h", 10) + .append("w", 15.25) + .append("uom", "cm") + ) + .append("status", "A"), + ) + ) + // End Example 6 + + // Start Example 9 + val flowFindEquality = collection.withDocumentClass() + .find(eq("status", "D")) + // End Example 9 + + flowFindEquality.collect { println(it) } + + // Start Example 10 + val flowFindOperator = collection.withDocumentClass() + .find(`in`("status", "A", "D")) + // End Example 10 + + flowFindOperator.collect { println(it) } + + // Start Example 11 + val flowFindAND = collection.withDocumentClass() + .find(and(eq("status", "A"), lt("qty", 30))) + // End Example 11 + + flowFindAND.collect { println(it) } + + // Start Example 12 + val flowFindOR = collection.withDocumentClass() + .find(or(eq("status", "A"), lt("qty", 30))) + // End Example 12 + + flowFindOR.collect { println(it) } + + // Start Example 13 + val flowFindANDOR = collection.withDocumentClass() + .find( + and(eq("status", "A"), + or(lt("qty", 30), regex("item", "^p"))) + ) + // End Example 13 + + flowFindANDOR.collect { println(it) } + collection.deleteMany(empty()) + + mongoClient.close() +} diff --git a/source/examples/generated/AggregatesBuilderTest.snippet.vector-search-data-class.kt b/source/examples/generated/AggregatesBuilderTest.snippet.vector-search-data-class.kt new file mode 100644 index 00000000..c632dbe5 --- /dev/null +++ b/source/examples/generated/AggregatesBuilderTest.snippet.vector-search-data-class.kt @@ -0,0 +1,6 @@ +data class MovieAlt( + val title: String, + val year: Int, + val plot: String, + val plotEmbedding: List +) diff --git a/source/examples/generated/AggregatesBuilderTest.snippet.vector-search.kt b/source/examples/generated/AggregatesBuilderTest.snippet.vector-search.kt new file mode 100644 index 00000000..7be37509 --- /dev/null +++ b/source/examples/generated/AggregatesBuilderTest.snippet.vector-search.kt @@ -0,0 +1,8 @@ +Aggregates.vectorSearch( + SearchPath.fieldPath(MovieAlt::plotEmbedding.name), + listOf(-0.0072121937, -0.030757688, -0.012945653), + "mflix_movies_embedding_index", + 2.toLong(), + 1.toLong(), + vectorSearchOptions().filter(Filters.gte(MovieAlt::year.name, 2016)) +) diff --git a/source/examples/generated/ChangeStreamsTest.snippet.split-large-change-stream.kt b/source/examples/generated/ChangeStreamsTest.snippet.split-large-change-stream.kt new file mode 100644 index 00000000..15f35830 --- /dev/null +++ b/source/examples/generated/ChangeStreamsTest.snippet.split-large-change-stream.kt @@ -0,0 +1,8 @@ +val pipeline = listOf(BsonDocument().append("\$changeStreamSplitLargeEvent", BsonDocument())) + +val job = launch { + val changeStream = collection.watch(pipeline) + changeStream.collect { + println("Received a change event: $it") + } +} diff --git a/source/examples/generated/KotlinXSerializationTest.snippet.kserializer-dataclass.kt b/source/examples/generated/KotlinXSerializationTest.snippet.kserializer-dataclass.kt new file mode 100644 index 00000000..490272a4 --- /dev/null +++ b/source/examples/generated/KotlinXSerializationTest.snippet.kserializer-dataclass.kt @@ -0,0 +1,7 @@ +@Serializable +data class PaintOrder( + val color: String, + val qty: Int, + @Serializable(with = InstantAsBsonDateTime::class) + val orderDate: Instant, +) diff --git a/source/examples/generated/KotlinXSerializationTest.snippet.kserializer.kt b/source/examples/generated/KotlinXSerializationTest.snippet.kserializer.kt new file mode 100644 index 00000000..0f538b81 --- /dev/null +++ b/source/examples/generated/KotlinXSerializationTest.snippet.kserializer.kt @@ -0,0 +1,17 @@ +object InstantAsBsonDateTime : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("InstantAsBsonDateTime", PrimitiveKind.LONG) + + override fun serialize(encoder: Encoder, value: Instant) { + when (encoder) { + is BsonEncoder -> encoder.encodeBsonValue(BsonDateTime(value.toEpochMilliseconds())) + else -> throw SerializationException("Instant is not supported by ${encoder::class}") + } + } + + override fun deserialize(decoder: Decoder): Instant { + return when (decoder) { + is BsonDecoder -> Instant.fromEpochMilliseconds(decoder.decodeBsonValue().asDateTime().value) + else -> throw SerializationException("Instant is not supported by ${decoder::class}") + } + } +} diff --git a/source/examples/generated/SearchIndexesTest.snippet.drop-search-index.kt b/source/examples/generated/SearchIndexesTest.snippet.drop-search-index.kt new file mode 100644 index 00000000..adf0f4e2 --- /dev/null +++ b/source/examples/generated/SearchIndexesTest.snippet.drop-search-index.kt @@ -0,0 +1 @@ +moviesCollection.dropSearchIndex("myIndex"); diff --git a/source/examples/generated/SearchIndexesTest.snippet.list-search-indexes.kt b/source/examples/generated/SearchIndexesTest.snippet.list-search-indexes.kt new file mode 100644 index 00000000..49e3f526 --- /dev/null +++ b/source/examples/generated/SearchIndexesTest.snippet.list-search-indexes.kt @@ -0,0 +1 @@ +val searchIndexesList = moviesCollection.listSearchIndexes().toList() diff --git a/source/examples/generated/SearchIndexesTest.snippet.multi-search-index-create.kt b/source/examples/generated/SearchIndexesTest.snippet.multi-search-index-create.kt new file mode 100644 index 00000000..238dcc8e --- /dev/null +++ b/source/examples/generated/SearchIndexesTest.snippet.multi-search-index-create.kt @@ -0,0 +1,16 @@ +val indexOne = SearchIndexModel( + "myIndex1", + Document("analyzer", "lucene.standard").append( + "mappings", Document("dynamic", true) + ) +) + +val indexTwo = SearchIndexModel( + "myIndex2", + Document("analyzer", "lucene.simple").append( + "mappings", Document("dynamic", true) + ) +) + +val resultCreateIndexes = moviesCollection + .createSearchIndexes(listOf(indexOne, indexTwo)) diff --git a/source/examples/generated/SearchIndexesTest.snippet.single-search-index-create.kt b/source/examples/generated/SearchIndexesTest.snippet.single-search-index-create.kt new file mode 100644 index 00000000..1266fd74 --- /dev/null +++ b/source/examples/generated/SearchIndexesTest.snippet.single-search-index-create.kt @@ -0,0 +1,5 @@ +val index = Document( + "mappings", + Document("dynamic", true) +) +val resultCreateIndex = moviesCollection.createSearchIndex("myIndex", index) diff --git a/source/examples/generated/SearchIndexesTest.snippet.update-search-indexes.kt b/source/examples/generated/SearchIndexesTest.snippet.update-search-indexes.kt new file mode 100644 index 00000000..a5ee0464 --- /dev/null +++ b/source/examples/generated/SearchIndexesTest.snippet.update-search-indexes.kt @@ -0,0 +1,14 @@ +moviesCollection.updateSearchIndex( + "myIndex", + Document("analyzer", "lucene.simple").append( + "mappings", + Document("dynamic", false) + .append( + "fields", + Document( + "title", + Document("type", "string") + ) + ) + ) +) diff --git a/source/examples/generated/SocksTest.snippet.socks-connection-string.kt b/source/examples/generated/SocksTest.snippet.socks-connection-string.kt new file mode 100644 index 00000000..d1c0aff0 --- /dev/null +++ b/source/examples/generated/SocksTest.snippet.socks-connection-string.kt @@ -0,0 +1,9 @@ +val connectionString = ConnectionString( + "mongodb+srv://:@/?" + + "proxyHost=" + + "&proxyPort=" + + "&proxyUsername=" + + "&proxyPassword=" +) + +val mongoClient = MongoClient.create(connectionString) diff --git a/source/examples/generated/SocksTest.snippet.socks-mongoclientsettings.kt b/source/examples/generated/SocksTest.snippet.socks-mongoclientsettings.kt new file mode 100644 index 00000000..f70ed151 --- /dev/null +++ b/source/examples/generated/SocksTest.snippet.socks-mongoclientsettings.kt @@ -0,0 +1,18 @@ +val uri = "" + +val mongoClient = MongoClient.create( + MongoClientSettings.builder() + .applyConnectionString(ConnectionString(uri)) + .applyToSocketSettings{ builder -> + builder + .applyToProxySettings{ proxyBuilder -> + proxyBuilder + .host("") + .port("".toInt()) + .username("") + .password("") + .build() + } + } + .build() +) diff --git a/source/examples/generated/UpdatesBuildersTest.snippet.add-to-set-update.kt b/source/examples/generated/UpdatesBuildersTest.snippet.add-to-set-update.kt index ae59839e..bc490fa8 100644 --- a/source/examples/generated/UpdatesBuildersTest.snippet.add-to-set-update.kt +++ b/source/examples/generated/UpdatesBuildersTest.snippet.add-to-set-update.kt @@ -1,3 +1,3 @@ val filter = Filters.eq("_id", 1) -val update = Updates.addToSet(PaintOrder::vendor.name, "C") +val update = Updates.addToSet(PaintOrder::vendor.name, Vendor("C")) collection.updateOne(filter, update) diff --git a/source/examples/generated/UpdatesBuildersTest.snippet.combine-update.kt b/source/examples/generated/UpdatesBuildersTest.snippet.combine-update.kt index faf0d884..2c56a424 100644 --- a/source/examples/generated/UpdatesBuildersTest.snippet.combine-update.kt +++ b/source/examples/generated/UpdatesBuildersTest.snippet.combine-update.kt @@ -2,6 +2,6 @@ val filter = Filters.eq("_id", 1) val update = Updates.combine( Updates.set(PaintOrder::color.name, "purple"), Updates.inc(PaintOrder::qty.name, 6), - Updates.push(PaintOrder::vendor.name, "R") + Updates.push(PaintOrder::vendor.name, Vendor("R")) ) collection.updateOne(filter, update) diff --git a/source/examples/generated/UpdatesBuildersTest.snippet.example-data-class.kt b/source/examples/generated/UpdatesBuildersTest.snippet.example-data-class.kt index 1a1dda2f..551f74d7 100644 --- a/source/examples/generated/UpdatesBuildersTest.snippet.example-data-class.kt +++ b/source/examples/generated/UpdatesBuildersTest.snippet.example-data-class.kt @@ -2,6 +2,10 @@ data class PaintOrder ( @BsonId val id: Int, val color: String, val qty: Int?, - val vendor: List?, + val vendor: List?, val lastModified: LocalDateTime? ) + +data class Vendor ( + val name: String, +) diff --git a/source/examples/generated/UpdatesBuildersTest.snippet.pull-all-update.kt b/source/examples/generated/UpdatesBuildersTest.snippet.pull-all-update.kt index 567e6164..1a51ba42 100644 --- a/source/examples/generated/UpdatesBuildersTest.snippet.pull-all-update.kt +++ b/source/examples/generated/UpdatesBuildersTest.snippet.pull-all-update.kt @@ -1,3 +1,3 @@ val filter = Filters.eq("_id", 1) -val update = Updates.pullAll(PaintOrder::vendor.name, listOf("A", "M")) +val update = Updates.pullAll(PaintOrder::vendor.name, listOf(Vendor("A"), Vendor("M"))) collection.updateOne(filter, update) diff --git a/source/examples/generated/UpdatesBuildersTest.snippet.pull-update.kt b/source/examples/generated/UpdatesBuildersTest.snippet.pull-update.kt index 3a50db8d..b99de03e 100644 --- a/source/examples/generated/UpdatesBuildersTest.snippet.pull-update.kt +++ b/source/examples/generated/UpdatesBuildersTest.snippet.pull-update.kt @@ -1,3 +1,3 @@ val filter = Filters.eq("_id", 1) -val update = Updates.pull(PaintOrder::vendor.name, "D") +val update = Updates.pull(PaintOrder::vendor.name, Vendor("D")) collection.updateOne(filter, update) diff --git a/source/examples/generated/UpdatesBuildersTest.snippet.push-update.kt b/source/examples/generated/UpdatesBuildersTest.snippet.push-update.kt index 6c69f150..17df170f 100644 --- a/source/examples/generated/UpdatesBuildersTest.snippet.push-update.kt +++ b/source/examples/generated/UpdatesBuildersTest.snippet.push-update.kt @@ -1,3 +1,3 @@ val filter = Filters.eq("_id", 1) -val update = Updates.push(PaintOrder::vendor.name, "Q") +val update = Updates.push(PaintOrder::vendor.name, Vendor("Q")) collection.updateOne(filter, update) diff --git a/source/faq.txt b/source/faq.txt index 2c0cd2b7..c42bd04d 100644 --- a/source/faq.txt +++ b/source/faq.txt @@ -4,20 +4,34 @@ FAQ === +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: troubleshooting, question, support + .. contents:: On this page :local: :backlinks: none :depth: 2 :class: singlecol -What if I can't connect to a MongoDB instance? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +On this page, you can find frequently asked questions and their corresponding answers. + +.. tip:: + + If you can't find an answer to your question on this page, see the + :ref:`kotlin-issues-and-help` page for information on how to report issues. + +Why Am I Having Problems Connecting to a MongoDB Instance? +---------------------------------------------------------- If you have trouble connecting to a MongoDB deployment, see the :ref:`Connection Troubleshooting Guide ` for possible solutions. -How Is the Kotlin Driver Different from Kmongo? +How is the Kotlin Driver Different from KMongo? ----------------------------------------------- The Kotlin driver is the official MongoDB driver for Kotlin. It is @@ -51,6 +65,22 @@ key differences: For more detailed information, see :ref:`Migrate from KMongo `. +What is the Difference Between the Kotlin Driver and the Kotlin SDK? +-------------------------------------------------------------------- + +MongoDB supports both mobile and server-side development in Kotlin. If +you are developing a mobile application for Android or Kotlin +Multiplatform (KMP), you can use the :realm:`MongoDB +Atlas Device Kotlin SDK ` to access Atlas App Services and +to manage your Realm data. + +The {+driver-short+} supports server-side development by providing a +complete library for building idiomatic Kotlin applications. You can +learn how to develop asynchronous applications in this documentation for +the Kotlin Coroutine Driver, or you can view the :driver:`Kotlin Sync +Driver documentation ` to learn more about synchronous +programming. + .. _kotlin-faq-connection-pool: How Does Connection Pooling Work in the Kotlin Driver? @@ -129,11 +159,5 @@ When ``MongoClient.close()`` is called by any thread, the driver closes all idle sockets and closes all sockets that are in use as they are returned to the pool. -To learn more about connecting to MongoDB, refer to the :ref:`Connection Guide `. - -Support -------- - -If you are unable to find the answer to your question here, try our forums and -support channels listed in the :doc:`Issues and Help ` -section. +To learn more about connecting to MongoDB, see the :ref:`Connection +Guide `. diff --git a/source/fundamentals.txt b/source/fundamentals.txt index 8b93057a..1ef41c30 100644 --- a/source/fundamentals.txt +++ b/source/fundamentals.txt @@ -1,3 +1,5 @@ +.. _kotlin-fundamentals-landing: + ============ Fundamentals ============ diff --git a/source/fundamentals/builders/aggregates.txt b/source/fundamentals/builders/aggregates.txt index 8d7ff868..c0eb34d9 100644 --- a/source/fundamentals/builders/aggregates.txt +++ b/source/fundamentals/builders/aggregates.txt @@ -4,6 +4,13 @@ Aggregates Builders =================== +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, data insights, compute, atlas + .. contents:: On this page :local: :backlinks: none @@ -668,7 +675,7 @@ The following examples use data modeled with the following Kotlin data class: .. literalinclude:: /examples/generated/AggregatesBuilderTest.snippet.bucket-data-class.kt :language: kotlin -This exampled creates a pipeline stage that will attempt to create and evenly +This example creates a pipeline stage that will attempt to create and evenly distribute documents into 5 buckets using the value of their ``price`` field: .. literalinclude:: /examples/generated/AggregatesBuilderTest.snippet.bucket-auto.kt @@ -898,3 +905,46 @@ aggregation stage: Learn more about this helper from the `searchMeta() API documentation <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Aggregates.html#searchMeta(com.mongodb.client.model.search.SearchCollector)>`__. +.. _kotlin-atlas-vector-search: + +Atlas Vector Search +------------------- + +.. important:: + + To learn about which versions of MongoDB Atlas support this feature, see + :atlas:`Limitations ` + in the Atlas documentation. + +Use the ``vectorSearch()`` method to create a :atlas:`$vectorSearch ` +pipeline stage that specifies a **semantic search**. A semantic search is +a type of search that locates pieces of information that are similar in meaning. + +To use this feature when performing an aggregation on a collection, you +must create a vector search index and index your vector embeddings. To +learn how to set up search indexes in MongoDB Atlas, see :atlas:`How to +Index Vector Embeddings for Vector Search +` in the Atlas documentation. + +The example in this section uses data modeled with the following Kotlin data class: + +.. literalinclude:: /examples/generated/AggregatesBuilderTest.snippet.vector-search-data-class.kt + :language: kotlin + +This example shows how to build an aggregation pipeline that uses the +``vectorSearch()`` method to perform a vector search with the following +specifications: + +- Searches ``plotEmbedding`` field values by using vector embeddings of a + string value +- Uses the ``mflix_movies_embedding_index`` vector search index +- Considers up to 2 nearest neighbors +- Returns 1 document +- Filters for documents in which the ``year`` value is at least ``2016`` + +.. literalinclude:: /examples/generated/AggregatesBuilderTest.snippet.vector-search.kt + :language: kotlin + +To learn more about this helper, see the +`vectorSearch() API documentation +<{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Aggregates.html#vectorSearch(com.mongodb.client.model.search.FieldSearchPath,java.lang.Iterable,java.lang.String,long,long)>`__. diff --git a/source/fundamentals/builders/updates.txt b/source/fundamentals/builders/updates.txt index f87b44b5..5f3e74e7 100644 --- a/source/fundamentals/builders/updates.txt +++ b/source/fundamentals/builders/updates.txt @@ -2,6 +2,13 @@ Updates Builders ================ +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, change data, nested class + .. contents:: On this page :local: :backlinks: none @@ -13,7 +20,7 @@ Updates Builders Overview -------- -In this guide, you can learn how to specify **updates** using +In this guide, you can learn how to specify **updates** by using :doc:`builders ` in the {+driver-long+}. The ``Updates`` builder provides helper methods for the following types of updates: @@ -48,7 +55,11 @@ The examples in this guide use the following document: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -82,7 +93,11 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 11, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -105,7 +120,11 @@ The preceding example updates the original document to the following state: { "_id": 1, "color": "red", - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -156,7 +175,11 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 8, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -181,7 +204,11 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 10, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -204,7 +231,11 @@ The preceding example updates the original document to the following state: { "_id": 1, "color": "red", - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" }, "quantity": 5, } @@ -231,7 +262,11 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 2, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -257,7 +292,11 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 8, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -284,7 +323,11 @@ the original document to the following state: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "$date": "2023-06-16T17:13:06.373Z" } @@ -311,7 +354,11 @@ the original document to the following state: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "$timestamp": { "t": 1686935654, "i": 3 } } @@ -349,7 +396,11 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 15, - "vendor": [ "A", "D", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -365,7 +416,8 @@ Use the `addToSet() <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/mode method to append a value to an array if the value is not already present in an update operation. -The following example adds the string ``"C"`` to the ``vendor`` array: +The following example adds a ``Vendor`` instance that has a ``name`` +value of ``"C"`` to the ``vendor`` array: .. literalinclude:: /examples/generated/UpdatesBuildersTest.snippet.add-to-set-update.kt :language: kotlin @@ -379,7 +431,12 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "A", "D", "M", "C" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" }, + { "name": "C" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -391,8 +448,7 @@ method to remove the first element of an array and the `popLast() <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Updates.html#popLast(java.lang.String)>`__ method to remove the last element of an array in an update operation. -The following example pops the first element off of the array value -of the ``vendor`` field: +The following example removes the first entry of the ``vendor`` array: .. literalinclude:: /examples/generated/UpdatesBuildersTest.snippet.pop-first-update.kt :language: kotlin @@ -406,7 +462,10 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "D", "M" ], + "vendor": [ + { "name": "D" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -417,7 +476,8 @@ Use the `pullAll() <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model method to remove all instances of specified values from an existing array in an update operation. -The following example removes vendor ``"A"`` and ``"M"`` from the ``vendor`` array: +The following example removes ``Vendor`` instances that have ``name`` values +of ``"A"`` and ``"M"`` from the ``vendor`` array: .. literalinclude:: /examples/generated/UpdatesBuildersTest.snippet.pull-all-update.kt :language: kotlin @@ -431,7 +491,9 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "D" ], + "vendor": [ + { "name": "D" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -442,8 +504,8 @@ Use the `pull() <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Up method to remove all instances of a specified value from an existing array in an update operation. -The following example removes the value ``"D"`` from the ``vendor`` -array: +The following example removes ``Vendor`` instances that have a ``name`` +value of ``"D"`` from the ``vendor`` array: .. literalinclude:: /examples/generated/UpdatesBuildersTest.snippet.pull-update.kt :language: kotlin @@ -457,7 +519,10 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "A", "M" ], + "vendor": [ + { "name": "A" }, + { "name": "M" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -467,7 +532,8 @@ Push Use the `push() <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Updates.html#push(java.lang.String,TItem)>`__ method to append a value to an array in an update operation. -The following examples adds ``"Q"`` to the ``vendor`` array: +The following example adds a ``Vendor`` instance that has a ``name`` +value of ``"Q"`` to the ``vendor`` array: .. literalinclude:: /examples/generated/UpdatesBuildersTest.snippet.push-update.kt :language: kotlin @@ -481,7 +547,12 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "red", "qty": 5, - "vendor": [ "A", "D", "M", "Q" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" }, + { "name": "Q" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } @@ -495,8 +566,8 @@ combining two or more of the update operators described in the preceding sections. The following example increments the value of the ``qty`` field by ``6``, sets -the value of the ``color`` field to ``"purple"``, and adds ``"R"`` to -the ``vendor`` field: +the value of the ``color`` field to ``"purple"``, and adds a ``Vendor`` +instance that has a ``name`` value of ``"R"`` to the ``vendor`` field: .. literalinclude:: /examples/generated/UpdatesBuildersTest.snippet.combine-update.kt :language: kotlin @@ -510,6 +581,11 @@ The preceding example updates the original document to the following state: "_id": 1, "color": "purple", "qty": 11, - "vendor": [ "A", "D", "M", "R" ], + "vendor": [ + { "name": "A" }, + { "name": "D" }, + { "name": "M" }, + { "name": "R" } + ], "lastModified": { "$date": "2000-01-01T07:00:00.000Z" } } diff --git a/source/fundamentals/connection.txt b/source/fundamentals/connection.txt index 2c808964..5c8de999 100644 --- a/source/fundamentals/connection.txt +++ b/source/fundamentals/connection.txt @@ -11,6 +11,7 @@ Connection Guide /fundamentals/connection/mongoclientsettings /fundamentals/connection/network-compression /fundamentals/connection/tls + /fundamentals/connection/socks5 .. contents:: On this page :local: @@ -30,6 +31,7 @@ sections: - :ref:`Specify Connection Behavior with the MongoClient Class ` - :ref:`Enable Network Compression ` - :ref:`Enable TLS/SSL on a Connection ` +- :ref:`Connect to MongoDB by Using a SOCKS5 Proxy ` For information about authenticating with a MongoDB instance, see :ref:`` and :ref:``. diff --git a/source/fundamentals/connection/mongoclientsettings.txt b/source/fundamentals/connection/mongoclientsettings.txt index a706757d..84943672 100644 --- a/source/fundamentals/connection/mongoclientsettings.txt +++ b/source/fundamentals/connection/mongoclientsettings.txt @@ -291,6 +291,10 @@ to modify the driver's behavior: * - ``applySettings()`` - Uses the socket settings specified in a ``SocketSettings`` object. + * - ``applyToProxySettings()`` + - Applies the ``ProxySettings.Builder`` block and then sets the + ``proxySettings`` field. + * - ``connectTimeout()`` - Sets the maximum time to connect to an available socket before throwing a timeout exception. diff --git a/source/fundamentals/connection/socks5.txt b/source/fundamentals/connection/socks5.txt new file mode 100644 index 00000000..e2049ad4 --- /dev/null +++ b/source/fundamentals/connection/socks5.txt @@ -0,0 +1,114 @@ +.. _kotlin-connect-socks: + +========================================== +Connect to MongoDB by Using a SOCKS5 Proxy +========================================== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, security, connection string + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to use the {+driver-long+} to connect +to MongoDB by using a **SOCKS5 proxy**. SOCKS5 is a standardized +protocol for communicating with network services through a proxy server. + +.. tip:: + + To learn more about the SOCKS5 protocol, see the Wikipedia entry on + :wikipedia:`SOCKS `. + +.. _kotlin-socks-proxy-settings: + +SOCKS5 Proxy Settings +--------------------- + +The proxy settings specify the SOCKS5 proxy server address and your +authentication credentials. You can specify your settings in an instance of +``MongoClientSettings`` or in your connection string. + +The following table describes the SOCKS5 client options: + +.. list-table:: + :header-rows: 1 + :widths: 15 20 65 + + * - Name + - Accepted Values + - Description + + * - **proxyHost** + - String + - Specifies the SOCKS5 proxy IPv4 address, IPv6 address, or hostname. + You must provide this value to connect to a SOCKS5 proxy. + + * - **proxyPort** + - Non-negative integer + - Specifies the TCP port number of the SOCKS5 proxy server. If you + set a value for ``proxyHost``, this option defaults to ``1080``, + but you can specify a different port number. + + * - **proxyUsername** + - String + - Specifies the username for authentication to the SOCKS5 proxy server. + The driver ignores ``null`` and empty string values for this setting. + The driver requires that you pass values for both ``proxyUsername`` + and ``proxyPassword`` or that you omit both values. + + * - **proxyPassword** + - String + - Specifies the password for authentication to the SOCKS5 proxy server. + The driver ignores ``null`` and empty string values for this setting. + The driver requires that you pass values for both ``proxyUsername`` + and ``proxyPassword`` or that you omit both values. + + +Examples +-------- + +The following examples show how to instantiate a ``MongoClient`` that connects +to MongoDB by using a SOCKS5 proxy. The proxy settings can be specified in a +``MongoClientSettings`` instance or a connection string. These examples use +the placeholder values described in the :ref:`kotlin-socks-proxy-settings` section. +Replace the placeholders with your proxy specifications and credentials. + +Specify Proxy Settings in the MongoClientSettings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code example shows how to specify SOCKS5 proxy settings by +using the ``applyToSocketSettings()`` builder method when creating a +``MongoClientSettings`` instance: + +.. literalinclude:: /examples/generated/SocksTest.snippet.socks-mongoclientsettings.kt + :language: kotlin + +Specify Proxy Settings in the Connection String +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code example shows how to specify SOCKS5 proxy settings in +your connection string: + +.. literalinclude:: /examples/generated/SocksTest.snippet.socks-connection-string.kt + :language: kotlin + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about the methods and types discussed in this guide, see the +following API documentation: + +- `MongoClientSettings.Builder <{+api+}/apidocs/mongodb-driver-core/com/mongodb/MongoClientSettings.Builder.html>`__ +- `SocketSettings.Builder <{+api+}/apidocs/mongodb-driver-core/com/mongodb/connection/SocketSettings.Builder.html>`__ +- `MongoClient.create() <{+api+}/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClients.html#create(com.mongodb.MongoClientSettings)>`__ +- `ProxySettings.Builder <{+api+}/apidocs/mongodb-driver-core/com/mongodb/connection/ProxySettings.Builder.html>`__ \ No newline at end of file diff --git a/source/fundamentals/connection/tls.txt b/source/fundamentals/connection/tls.txt index 3e4ec28f..f8eb05ae 100644 --- a/source/fundamentals/connection/tls.txt +++ b/source/fundamentals/connection/tls.txt @@ -4,6 +4,13 @@ Enable TLS/SSL on a Connection ============================== +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, security, authentication + .. contents:: On this page :local: :backlinks: none @@ -23,7 +30,7 @@ or `MongoClientSettings <{+api+}/apidocs/mongodb-driver-core/com/mongodb/MongoCl .. note:: Debugging TLS/SSL If you experience trouble setting up your TLS/SSL connection, you can - use the ``-Djavax.net.debug=all`` system property to view additional + use the ``-Djavax.net.debug=all`` system property to view more log statements. See `the Oracle guide to debugging TLS/SSL connections `__ for more information. @@ -37,6 +44,19 @@ You can enable TLS/SSL for the connection to your MongoDB instance in two different ways: through a parameter in your connection string, or using a method in the ``MongoClientSettings.Builder`` class. +.. note:: DNS Seedlist Protocol Enables TLS + + If you connect by using the DNS seedlist protocol, indicated by the + ``mongodb+srv`` prefix in your connection string, the driver + automatically enables TLS/SSL. To disable it, set the ``tls`` + parameter value to ``false`` in your connection string, or set the + ``enabled`` property to ``false`` in the ``SslSettings.Builder`` + block when creating a ``MongoClientSettings`` instance. + + To learn more about connection behavior when you use a DNS seedlist, + see the :manual:`SRV Connection Format ` + section in the Server manual. + .. tabs:: .. tab:: ConnectionString @@ -69,7 +89,7 @@ Configure Certificates Kotlin applications that initiate TLS/SSL requests require access to cryptographic certificates that prove identity for the application -itself as well as other applications with which the application +itself and other applications with which the application interacts. You can configure access to these certificates in your application with the following mechanisms: @@ -104,7 +124,7 @@ application is genuine and secure from tampering by third parties. If your MongoDB instance uses a certificate that is signed by an authority that is not present in the JRE's default certificate store, your application must configure two system properties to initiate -SSL/TLS requests. These properties ensure that your application is able to +SSL/TLS requests. These properties ensure that your application can validate the TLS/SSL certificate presented by a connected MongoDB instance. - ``javax.net.ssl.trustStore``: the path to a trust store containing the @@ -128,8 +148,8 @@ Configure the JVM Key Store .. note:: By default, MongoDB instances do not perform client certificate - validation. You only need to configure the key store if you explicitly - configured your MongoDB instance to validate client certificates. + validation. You must configure the key store if you configured your MongoDB + instance to validate client certificates. The JVM key store saves certificates that securely identify your Kotlin application to other applications. Using these certificates, other @@ -148,11 +168,11 @@ the MongoDB server: You can create a key store with the `keytool `__ -or `openssl `__ command -line tools. +or `openssl `__ +command line tool. For more information on configuring a Kotlin application to use TLS/SSL, -please refer to the `JSSE Reference Guide +please see the `JSSE Reference Guide `__. .. _tls-disable-hostname-verification: @@ -175,7 +195,7 @@ Disable Hostname Verification By default, the driver ensures that the hostname included in the server's TLS/SSL certificates matches the hostnames provided when constructing -a ``MongoClient``. If you need to disable hostname verification for your +a ``MongoClient``. To disable hostname verification for your application, you can explicitly disable this by setting the ``invalidHostNameAllowed`` property of the builder to ``true`` in the ``applytoSslSettings()`` builder lambda: @@ -187,7 +207,7 @@ application, you can explicitly disable this by setting the Disabling hostname verification can make your configuration `insecure `__. - You should only disable hostname verification for testing purposes or + Disable hostname verification only for testing purposes or when there is no other alternative. .. _tls-restrict-tls-1.2: @@ -200,17 +220,17 @@ To restrict your application to use only the TLS 1.2 protocol, set the .. note:: - Java Runtime Environments (JREs) prior to Java 8 only enabled + Java Runtime Environments (JREs) before Java 8 only enabled the TLS 1.2 protocol in update releases. If your JRE has not enabled - the TLS 1.2 protocol, you may need to upgrade to a later release to - connect using TLS 1.2. + the TLS 1.2 protocol, upgrade to a later release to connect by using + TLS 1.2. .. _tls-custom-sslContext: Customize TLS/SSL Configuration through the Java SE SSLContext -------------------------------------------------------------- -If your TLS/SSL configuration requires additional customization, you can +If your TLS/SSL configuration requires customization, you can set the ``sslContext`` property of your ``MongoClient`` by passing an `SSLContext `__ @@ -254,7 +274,7 @@ Online Certificate Status Protocol (OCSP) OCSP is a standard used to check whether X.509 certificates have been revoked. A certificate authority can add an X.509 certificate to the -Certificate Revocation List (CRL) prior to the expiry time to invalidate +Certificate Revocation List (CRL) before the expiry time to invalidate the certificate. When a client sends an X.509 certificate during the TLS handshake, the CA's revocation server checks the CRL and returns a status of "good", "revoked", or "unknown". @@ -328,7 +348,7 @@ properties: | | If unset or set to ``false``, the connection can proceed regardless of the presence or status of the certificate revocation response. -For additional information about OCSP, check out the following resources: +For more information about OCSP, check out the following resources: - Oracle JDK 8 Documentation on `how to enable OCSP for an application `__ - :rfc:`Official IETF specification for OCSP (RFC 6960) <6960>` diff --git a/source/fundamentals/crud/read-operations/change-streams.txt b/source/fundamentals/crud/read-operations/change-streams.txt index 0e50b1eb..347d95ad 100644 --- a/source/fundamentals/crud/read-operations/change-streams.txt +++ b/source/fundamentals/crud/read-operations/change-streams.txt @@ -5,6 +5,13 @@ Open Change Streams =================== +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, monitoring, aggregation + .. contents:: On this page :local: :backlinks: none @@ -18,15 +25,16 @@ In this guide, you can learn how to use a **change stream** to monitor real-time changes to your database. A change stream is a {+mdb-server+} feature that allows your application to subscribe to data changes on a single collection, database, or deployment. You can specify a set of aggregation -operators to filter and transform the data your application receives. When -connecting to a MongoDB deployment v6.0 or later, you can configure the -events to include the document data before and after the change. +operators to filter and transform the data your application receives. +When connecting to MongoDB v6.0 or later, you can configure the events +to include the document data before and after the change. Learn how to open and configure your change streams in the following sections: - :ref:`` - :ref:`` +- :ref:`` - :ref:`` .. _kotlin-change-stream-open: @@ -107,9 +115,8 @@ The following code example shows how you can apply an aggregation pipeline to configure your change stream to receive change events for only insert and update operations: - .. literalinclude:: /examples/generated/ChangeStreamsTest.snippet.apply-aggregation-operations-to-change-stream.kt - :language: java + :language: kotlin When the change stream receives an update change event, the preceding code example outputs the following text: @@ -122,6 +129,55 @@ example outputs the following text: resumeToken={...}, ... +.. _kotlin-change-stream-split-large-event: + +Split Large Change Stream Events +-------------------------------- + +When connecting to MongoDB v7.0 or later, +you can use the ``$changeStreamSplitLargeEvent`` aggregation operator to +split event documents that exceed 16 MB into smaller fragments. + +Use the ``$changeStreamSplitLargeEvent`` operator only when you expect +the change stream events to exceed the document size limit. For +example, you might use this feature if your application requires full +document pre-images or post-images. + +A ``$changeStreamSplitLargeEvent`` aggregation stage returns +fragments sequentially. You can access the fragments by using a change +stream cursor. Each fragment document includes a ``splitEvent`` object that +contains the following fields: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Field + - Description + + * - ``fragment`` + - The index of the fragment, starting at ``1`` + + * - ``of`` + - The total number of fragments that compose the split event + +The following example opens a change stream that includes an aggregation +pipeline with an ``$changeStreamSplitLargeEvent`` aggregation stage to +split large events: + +.. literalinclude:: /examples/generated/ChangeStreamsTest.snippet.split-large-change-stream.kt + :language: kotlin + +.. note:: + + You can have only one ``$changeStreamSplitLargeEvent`` stage in your + aggregation pipeline, and it must be the last stage in the pipeline. + +To learn more about the ``$changeStreamSplitLargeEvent`` aggregation operator, +see :manual:`$changeStreamSplitLargeEvent (aggregation) +` in the +Server manual. + .. _kotlin-change-stream-configure-pre-post: Include Pre-images and Post-images diff --git a/source/fundamentals/data-formats/documents.txt b/source/fundamentals/data-formats/documents.txt index 54e492a6..c19af974 100644 --- a/source/fundamentals/data-formats/documents.txt +++ b/source/fundamentals/data-formats/documents.txt @@ -277,7 +277,7 @@ see the following API Documentation: - `JsonObject <{+api+}/apidocs/bson/org/bson/json/JsonObject.html>`__ - `JsonObjectCodec <{+api+}/apidocs/bson/org/bson/codecs/JsonObjectCodec.html>`__ - `JsonWriterSettings <{+api+}/apidocs/bson/org/bson/json/JsonWriterSettings.html>`__ -- `getCollection() `__ +- `getCollection() <{+api+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-database/get-collection.html>`__ Summary ------- diff --git a/source/fundamentals/data-formats/serialization.txt b/source/fundamentals/data-formats/serialization.txt index d28013af..5ce30648 100644 --- a/source/fundamentals/data-formats/serialization.txt +++ b/source/fundamentals/data-formats/serialization.txt @@ -4,6 +4,13 @@ Kotlin Serialization ==================== +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, data model, conversion + .. contents:: On this page :local: :backlinks: none @@ -13,25 +20,28 @@ Kotlin Serialization Overview -------- -The Kotlin driver supports the ``kotlinx.serialization`` library for serializing -and deserializing Kotlin objects. +The {+driver-short+} supports the ``kotlinx.serialization`` library for +serializing and deserializing Kotlin objects. -The driver provides an efficient ``Bson`` serializer that can can be used with +The driver provides an efficient ``Bson`` serializer that you can use with classes marked as ``@Serializable`` to handle the serialization of Kotlin objects -to BSON data. -The ``bson-kotlinx`` library also supports :ref:`custom codecs ` -with configurations to encode defaults, encode nulls, and define class -discriminators. +to BSON data. + +You can also install the ``bson-kotlinx`` library to support +:ref:`custom codecs ` with configurations to encode +defaults, encode nulls, and define class discriminators. .. note:: - To use the ``Codec`` interface instead of the Kotlin serialization library - to specify custom encoding and decoding of Kotlin objects to BSON data, - see the :ref:`Codecs ` documentation. You might choose - Kotlin serialization if you are already familiar with the framework or - you prefer to use an idiomatic Kotlin approach. + To learn how to use the ``Codec`` interface instead of the + Kotlin serialization library to specify custom encoding and decoding + of Kotlin objects to BSON data, see the :ref:`Codecs + ` guide. + + You might choose Kotlin serialization if you are already familiar + with the framework or if you prefer to use an idiomatic Kotlin approach. -Although you can use the Kotlin driver with the Kotlin serialization ``Json`` +Although you can use the {+driver-short+} with the Kotlin serialization ``Json`` library, the ``Json`` serializer does *not* directly support BSON value types such as ``ObjectId``. You must provide a custom serializer that can handle the conversion between BSON and JSON. @@ -39,21 +49,20 @@ conversion between BSON and JSON. Supported Types ~~~~~~~~~~~~~~~ -The Kotlin driver supports: +The {+driver-short+} supports: - All Kotlin types that are supported by the Kotlin serialization library - All available :manual:`BSON types ` -You can implement a custom serializers to handle any other types. See the -`official Kotlin Documentation `__ -for more information. - Add Kotlin Serialization to Your Project ---------------------------------------- -The Kotlin driver serialization support depends on the official Kotlin -serialization library. You must add `Kotlin Serialization `__ -to your project: +Support for serialization in the {+driver-short+} depends on the official `Kotlin +serialization library `__. + +Select from the following tabs to see how to add the serialization +dependencies to your project by using the :guilabel:`Gradle` and +:guilabel:`Maven` package managers: .. tabs:: @@ -96,7 +105,7 @@ To declare a class as serializable, annotate your Kotlin data classes with the ``@Serializable`` annotation from the Kotlin serialization framework. You can use your data classes in your code as normal after you mark them as serializable. -The Kotlin driver and the Kotlin serialization framework will handle the +The {+driver-short+} and the Kotlin serialization framework handle the BSON serialization and deserialization. This example shows a simple data class annotated with the following: @@ -120,6 +129,38 @@ For more information on serializable classes and available annotation classes, see the `official Kotlin Serialization `__ documentation. +Custom Serializer Example +~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can create a custom serializer to handle how your data is +represented in BSON. The {+driver-short+} uses the ``KSerializer`` +interface from the ``kotlinx.serialization`` package to implement custom +serializers. You can specify the custom serializer as the parameter to +the ``@Serializable`` annotation for a specific field. + +The following example shows how to create a custom +``KSerializer`` instance to convert a ``kotlinx.datetime.Instant`` to a +``BsonDateTime``: + +.. literalinclude:: /examples/generated/KotlinXSerializationTest.snippet.kserializer.kt + :language: kotlin + +The following code shows the ``PaintOrder`` data class in which the +``orderDate`` field has an annotation that specifies the custom +serializer class defined in the preceding code: + +.. literalinclude:: /examples/generated/KotlinXSerializationTest.snippet.kserializer-dataclass.kt + :language: kotlin + :emphasize-lines: 5 + +For more information about the methods and classes mentioned in this section, +see the following API documentation: + +- `KSerializer <{+kotlin-docs+}/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/>`__ +- `Instant <{+kotlin-docs+}/api/kotlinx-datetime/kotlinx-datetime/kotlinx.datetime/-instant/>`__ +- `BsonEncoder <{+api+}/apidocs/bson-kotlinx/bson-kotlinx/org.bson.codecs.kotlinx/-bson-encoder/index.html>`__ +- `BsonDecoder <{+api+}/apidocs/bson-kotlinx/bson-kotlinx/org.bson.codecs.kotlinx/-bson-decoder/index.html>`__ + .. _kotlin-custom-codec: Customize the Serializer Configuration @@ -132,7 +173,10 @@ customize what is stored. Use the ``BsonConfiguration`` class to define the configuration, including whether to encode defaults, encode nulls, or define class discriminators. -To create a custom codec, install the ``bson-kotlinx`` dependency to your project. +To create a custom codec, install the ``bson-kotlinx`` +dependency to your project. Select from the following tabs to see how to +add the dependency to your project by using the :guilabel:`Gradle` and +:guilabel:`Maven` package managers: .. tabs:: @@ -162,8 +206,25 @@ To create a custom codec, install the ``bson-kotlinx`` dependency to your projec {+full-version+} -Then, you can define your codec using the `KotlinSerializerCodec.create() `__ -method and add it to the registry. +.. note:: bson-kotlin Dependency + + You can also optionally install the ``bson-kotlin`` dependency + through the default codec registry. This dependency uses reflection + and the codec registry to support Kotlin data classes, but it does + not support certain POJO annotations such as ``BsonDiscriminator``, + ``BsonExtraElements``, and ``BsonConstructor``. To learn more, see + the `bson-kotlin API documentation <{+api+}/apidocs/bson-kotlin/index.html>`__. + + Generally, we recommend that you install and use the faster + ``bson-kotlinx`` library for codec configuration. + +Then, you can define your codec using the +`KotlinSerializerCodec.create() +<{+api+}/apidocs/bson-kotlinx/bson-kotlinx/org.bson.codecs.kotlinx/-kotlin-serializer-codec/-companion/index.html>`__ +method and add it to the registry. + +Custom Codec Example +~~~~~~~~~~~~~~~~~~~~ The following example shows how to create a codec using the ``KotlinSerializerCodec.create()`` method and configure it to not encode defaults: @@ -179,7 +240,7 @@ The following example shows how to create a codec using the :language: kotlin For more information about the methods and classes mentioned in this section, -see the following API Documentation: +see the following API documentation: - `KotlinSerializerCodec <{+api+}/apidocs/bson-kotlinx/bson-kotlinx/org.bson.codecs.kotlinx/-kotlin-serializer-codec/index.html>`__ - `KotlinSerializerCodec.create() <{+api+}/apidocs/bson-kotlinx/bson-kotlinx/org.bson.codecs.kotlinx/-kotlin-serializer-codec/-companion/create.html>`__ diff --git a/source/fundamentals/indexes.txt b/source/fundamentals/indexes.txt index 6558f799..305384c4 100644 --- a/source/fundamentals/indexes.txt +++ b/source/fundamentals/indexes.txt @@ -4,6 +4,13 @@ Indexes ======= +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, optimization, atlas search + .. contents:: On this page :local: :backlinks: none @@ -13,25 +20,30 @@ Indexes Overview -------- -In this guide, you can learn how to use **indexes** with the MongoDB Kotlin driver. +In this guide, you can learn how to create and manage **indexes** by +using the {+driver-long+}. + +Indexes support the efficient execution of queries in MongoDB. Without +indexes, MongoDB must scan *every* document in a collection (a +**collection scan**) to find the documents that match each query. These +collection scans are slow and can negatively affect the performance of +your application. If an appropriate index exists for a query, MongoDB +can use the index to limit the documents that the query must inspect. -Indexes support the efficient execution of queries in MongoDB. Without indexes, MongoDB must scan *every* document in a -collection (a **collection scan**) to find the documents that match each query. These collection scans are slow and can -negatively affect the performance of your application. If an appropriate index exists for a query, MongoDB can use the -index to limit the number of documents it must inspect. +Indexes also have the following benefits: -Indexes also: +- Indexes allow efficient sorting. +- Indexes enable special capabilities such as :ref:`geospatial queries `. +- Indexes allow the creation of constraints to ensure a field value is :ref:`unique `. -- Allow efficient sorting -- Enable special capabilities like :ref:`geospatial ` search -- Allow adding constraints to ensure a field value is :ref:`unique ` -- And :manual:`more ` +To learn more, see :manual:`Indexes ` in the Server manual. .. tip:: - Indexes are also used by update operations when finding the documents to update, delete operations when finding the - documents to delete, and by :manual:`certain stages ` in - the aggregation pipeline. + Update operations use indexes when finding documents to update, and + delete operations use indexes when finding documents to delete. + :manual:`Certain stages ` in + the aggregation pipeline also use indexes to improve performance. Query Coverage and Performance ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -39,9 +51,9 @@ Query Coverage and Performance When you execute a query against MongoDB, your command can include various elements: - Query criteria that specify fields and values you are looking for -- Options that affect the query's execution (e.g. read concern) -- Projection criteria to specify the fields MongoDB should return (optional) -- Sort criteria to specify the order documents will be returned from MongoDB (optional) +- Options that affect the query's execution, such as the read concern +- Projection criteria to specify the fields MongoDB returns (optional) +- Sort criteria to specify the order of documents returned from MongoDB (optional) When all the fields specified in the query, projection, and sort are in the same index, MongoDB returns results directly from the index, also called a **covered query**. @@ -57,24 +69,32 @@ from the index, also called a **covered query**. name_1_age_-1 - MongoDB would use this index when you sort your data by either: + MongoDB uses this index when you sort your data in either of the + following ways: - ``name`` ascending, ``age`` descending - ``name`` descending, ``age`` ascending Specifying a sort order of ``name`` and :guilabel:`age` ascending or :guilabel:`name` and ``age`` - descending would require an in-memory sort. + descending requires an in-memory sort. -For additional information on how to ensure your index covers your query criteria and projection, see the MongoDB manual +For more information on how to ensure your index covers your query criteria and projection, see the Server manual articles on :manual:`query coverage `. Operational Considerations ~~~~~~~~~~~~~~~~~~~~~~~~~~ -To improve query performance, build indexes on fields that appear often in your application's queries and operations -that return sorted results. Each index that you add consumes disk space and memory when active so you should track index -memory and disk usage for capacity planning. In addition, when a write operation updates an indexed field, MongoDB also -has to update the related index. +The following guidelines describe how you can optimize the way +your application uses indexes: + +- To improve query performance, build indexes on fields that appear often in + your application's queries and operations that return sorted results. + +- Track index memory and disk usage for capacity planning, because each + index that you add consumes disk space and memory when active. + +- Avoid adding indexes that you infrequently use. Note that when a write + operation updates an indexed field, MongoDB updates the related index. Since MongoDB supports dynamic schemas, applications can query against fields whose names cannot be known in advance or are arbitrary. MongoDB 4.2 introduced :manual:`wildcard indexes ` to help support these queries. @@ -87,14 +107,17 @@ server documentation on :manual:`Indexing Strategies ` an Index Types ----------- -MongoDB supports a number of different index types to support querying your data. The following sections describe the +MongoDB supports several different index types to support querying your data. The following sections describe the most common index types and provide sample code for creating each index type. For a full list of index types, see -:manual:`Indexes `. +:manual:`Indexes ` in the Server manual. .. tip:: - The MongoDB Kotlin driver provides the `Indexes <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html>`__ class that - includes static factory methods to create index specification documents for different MongoDB Index key types. + The {+driver-short+} provides the `Indexes + <{+api+}/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html>`__ + class to create and manage indexes. This class includes static + factory methods to create index specification documents for different + MongoDB index key types. The following examples use the `createIndex() <{+api+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-collection/create-index.html>`__ @@ -131,7 +154,8 @@ The following example creates an index in ascending order on the ``title`` field Index created: title_1 -The following is an example of a query that would be covered by the index created in the preceding code snippet: +The following is an example of a query that is covered by the index +created in the preceding code snippet: .. literalinclude:: /examples/generated/IndexesTest.snippet.single-index-query.kt :language: kotlin @@ -160,7 +184,8 @@ The following example creates a compound index on the ``type`` and ``rated`` fie Index created: type_1_rated_1 -The following is an example of a query that would be covered by the index created in the preceding code snippet: +The following is an example of a query that is covered by the index +created in the preceding code snippet: .. literalinclude:: /examples/generated/IndexesTest.snippet.compound-index-query.kt :language: kotlin @@ -186,14 +211,101 @@ Strings), and ``title`` fields: Index created: rated_1_genres_1_title_1 -The following is an example of a query that would be covered by the index created in the preceding code snippet: +The following is an example of a query that is covered by the index +created in the preceding code snippet: .. literalinclude:: /examples/generated/IndexesTest.snippet.multikey-index-query.kt :language: kotlin -Multikey indexes behave differently from non-multikey indexes in terms of query coverage, index bound computation, and -sort behavior. For a full explanation of multikey indexes, including a discussion of their behavior and limitations, -refer to the :manual:`Multikey Indexes page ` in the MongoDB manual. +Multikey indexes behave differently from other indexes in terms of query coverage, index-bound computation, and +sort behavior. To learn more about multikey indexes, including a discussion of their behavior and limitations, +see :manual:`Multikey Indexes ` in the Server manual. + +.. _kotlin-search-indexes: + +Atlas Search Indexes +~~~~~~~~~~~~~~~~~~~~ + +The Atlas Search feature enables you to perform full-text searches on +collections hosted on MongoDB Atlas. The indexes specify how you can +perform full-text searches on specific fields. + +To learn more about MongoDB Atlas Search, see the +:atlas:`Atlas Search Indexes ` +documentation. + +You can call the following methods on a collection to manage your Atlas Search +indexes: + +- ``createSearchIndex()`` +- ``createSearchIndexes()`` +- ``listSearchIndexes()`` +- ``updateSearchIndex()`` +- ``dropSearchIndex()`` + +.. note:: + + The Atlas Search index-management methods run asynchronously. The + driver methods can return before confirming that they ran + successfully. To determine the current status of the indexes, call the + ``listSearchIndexes()`` method. + +The following sections provide code examples that demonstrate how to use +each of the preceding methods. + +Create a Search Index ++++++++++++++++++++++ + +You can use the `createSearchIndex() <{+api+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-collection/create-search-index.html>`__ +and `createSearchIndexes() <{+api+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-collection/create-search-indexes.html>`__ +methods to create Atlas Search indexes on a collection. + +The following code example shows how to create a single index: + +.. literalinclude:: /examples/generated/SearchIndexesTest.snippet.single-search-index-create.kt + :language: kotlin + +The following code example shows how to create multiple indexes: + +.. literalinclude:: /examples/generated/SearchIndexesTest.snippet.multi-search-index-create.kt + :language: kotlin + +List Search Indexes ++++++++++++++++++++ + +You can use the +`listSearchIndexes() <{+api+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-collection/list-search-indexes.html>`__ +method to return a list of the Atlas Search indexes on a collection. + +The following code example shows how to print a list of the search indexes on +a collection: + +.. literalinclude:: /examples/generated/SearchIndexesTest.snippet.list-search-indexes.kt + :language: kotlin + +Update a Search Index ++++++++++++++++++++++ + +You can use the +`updateSearchIndex() <{+api+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-collection/update-search-index.html>`__ +method to update an Atlas Search index. + +The following code shows how to update a search index: + +.. literalinclude:: /examples/generated/SearchIndexesTest.snippet.update-search-indexes.kt + :language: kotlin + +Drop a Search Index ++++++++++++++++++++ + +You can use the +`dropSearchIndex() <{+api+}/apidocs/mongodb-driver-kotlin-coroutine/mongodb-driver-kotlin-coroutine/com.mongodb.kotlin.client.coroutine/-mongo-collection/drop-search-index.html>`__ +method to remove an Atlas Search index. + +The following code shows how to delete a search index from a collection: + +.. literalinclude:: /examples/generated/SearchIndexesTest.snippet.drop-search-index.kt + :language: kotlin .. _text-indexes: @@ -206,9 +318,10 @@ language as an option when creating the index. .. tip:: - Text indexes differ from the more powerful - :atlas:`Atlas full text search indexes `. - Atlas users should use Atlas Search. + MongoDB offers an improved full-text search solution, + :atlas:`Atlas Search `. To learn more about Atlas Search + indexes and how to use them, see the :ref:`kotlin-search-indexes` section of this + guide. Single Field ++++++++++++ @@ -225,7 +338,8 @@ The following example creates a text index on the ``plot`` field: Index created: plot_text -The following is an example of a query that would use the index created in the preceding code snippet. Note that the ``sort`` is +The following is an example of a query that is covered by the index +created in the preceding code snippet. Note that the ``sort`` is omitted because text indexes do not contain sort order. .. literalinclude:: /examples/generated/IndexesTest.snippet.text-index-query.kt @@ -235,7 +349,7 @@ Multiple Fields +++++++++++++++ A collection can only contain one text index. If you want to create a -text index for multiple text fields, you need to create a compound +text index for multiple text fields, you must create a compound index. A text search runs on all the text fields within the compound index. @@ -264,10 +378,11 @@ Geospatial Indexes MongoDB supports queries of geospatial coordinate data using **2dsphere indexes**. With a ``2dsphere`` index, you can query the geospatial data for inclusion, intersection, and proximity. For more information on querying geospatial data, see -:manual:`Geospatial Queries `. +:manual:`Geospatial Queries ` in the Server manual. -To create a ``2dsphere`` index, you must specify a field that contains only **GeoJSON objects**. For more details on this -type, see the MongoDB server manual page on :manual:`GeoJSON objects `. +To create a ``2dsphere`` index, you must specify a field that contains +only **GeoJSON objects**. To learn more about this type, see +:manual:`GeoJSON objects ` in the Server manual. The ``location.geo`` field in the following sample document from the ``theaters`` collection in the ``sample_mflix`` database is a GeoJSON Point object that describes the coordinates of the theater: @@ -307,15 +422,21 @@ The following example creates a ``2dsphere`` index on the ``location.geo`` field Index created: location.geo_2dsphere -The following is an example of a geospatial query using the index created -in the preceding code snippet: +.. important:: + + Attempting to create a geospatial index on a field that is already + covered by a geospatial index results in an error. + +The following is an example of a geospatial query that is covered by the index +created in the preceding code snippet: .. literalinclude:: /examples/generated/IndexesTest.snippet.geospatial-index-query.kt :language: kotlin -MongoDB also supports ``2d`` indexes for calculating distances on a Euclidean plane and for working with the "legacy -coordinate pairs" syntax used in MongoDB 2.2 and earlier. See the :manual:`Geospatial Queries page ` -in the MongoDB server manual for more information. +MongoDB also supports ``2d`` indexes for calculating distances on a +Euclidean plane and for working with the "legacy coordinate pairs" +syntax used in MongoDB 2.2 and earlier. To learn more, see +:manual:`Geospatial Queries ` in the Server manual. Unique Indexes ~~~~~~~~~~~~~~ @@ -340,8 +461,9 @@ The following example creates a unique, descending index on the ``theaterId`` fi .. important:: - If you perform a write operation that stores a duplicate value that violates the unique index, the MongoDB - Kotlin driver will raise a ``DuplicateKeyException``, and MongoDB will throw an error resembling the following: + If you perform a write operation that stores a duplicate value that + violates the unique index, the driver raises a ``DuplicateKeyException``, + and MongoDB throws an error resembling the following: .. code-block:: none :copyable: false @@ -411,7 +533,7 @@ Remove an Index Using a Name Field Pass the ``name`` field of the index to the ``dropIndex()`` method to remove an index from a collection. -If you need to find the name of your index, use the ``listIndexes()`` +If you must find the name of your index, use the ``listIndexes()`` method to see the value of the ``name`` fields in your indexes. The following snippet retrieves and prints all the indexes in a diff --git a/source/includes/serialization-libs-gradle-versioned.rst b/source/includes/serialization-libs-gradle-versioned.rst new file mode 100644 index 00000000..ac994c76 --- /dev/null +++ b/source/includes/serialization-libs-gradle-versioned.rst @@ -0,0 +1,8 @@ +.. code-block:: kotlin + :caption: build.gradle.kts + :copyable: true + + implementation("org.mongodb:bson-kotlinx:{+full-version+}") + // OR + implementation("org.mongodb:bson-kotlin:{+full-version+}") + \ No newline at end of file diff --git a/source/includes/serialization-libs-maven-versioned.rst b/source/includes/serialization-libs-maven-versioned.rst new file mode 100644 index 00000000..16ba6eb6 --- /dev/null +++ b/source/includes/serialization-libs-maven-versioned.rst @@ -0,0 +1,16 @@ +.. code-block:: xml + :caption: pom.xml + :copyable: true + + + org.mongodb + bson-kotlinx + {+full-version+} + + + + org.mongodb + bson-kotlin + {+full-version+} + + \ No newline at end of file diff --git a/source/index.txt b/source/index.txt index cbfd973c..12b0850b 100644 --- a/source/index.txt +++ b/source/index.txt @@ -23,14 +23,20 @@ Introduction ------------ Welcome to the documentation site for the Kotlin Driver, the official -MongoDB driver for server-side Kotlin applications using coroutines. Download it using -`Maven `__ or -`Gradle `__, or set up a runnable project by -following our Quick Start guide. - -If your Kotlin application requires synchronous processing, use the -:driver:`Sync Driver ` which uses synchronous operations -to make blocking calls to MongoDB. +MongoDB driver for server-side Kotlin applications that use coroutines. +Download the driver by using `Maven `__ or `Gradle +`__, or set up a runnable project by following our +Quick Start guide. + +.. tip:: Other Kotlin Platforms for MongoDB + + If your Kotlin application requires synchronous processing, use the + :driver:`Sync Driver `, which uses synchronous operations + to make blocking calls to MongoDB. + + If you are developing an Android or Kotlin Multiplatform (KMP) + application, you can use the :realm:`MongoDB Atlas Device Kotlin SDK ` + to access Atlas App Services and to manage your Realm data. Quick Start ----------- diff --git a/source/quick-start.txt b/source/quick-start.txt index cb0b143c..29e30933 100644 --- a/source/quick-start.txt +++ b/source/quick-start.txt @@ -4,6 +4,13 @@ Quick Start =========== +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :keywords: code example, get started, runnable app + .. contents:: On this page :local: :backlinks: none @@ -13,27 +20,25 @@ Quick Start Introduction ------------ -This guide shows you how to create an application that uses the **Kotlin driver** -to connect to a **MongoDB Atlas cluster**. If you prefer to connect to MongoDB -using a different driver or programming language, see our +This guide shows you how to create an application that uses the **{+driver-short+}** +to connect to a **MongoDB Atlas cluster**. If you prefer to connect to +MongoDB by using a different driver or programming language, see the :driver:`list of official MongoDB drivers <>`. -The Kotlin driver lets you connect to and communicate with MongoDB clusters +The {+driver-short+} lets you connect to and communicate with MongoDB clusters from a Kotlin application. -MongoDB Atlas is a fully-managed cloud database service that hosts your data -on MongoDB clusters. In this guide, we show you how to get started with your -own free (no credit card required) cluster. +MongoDB Atlas is a fully managed cloud database service that hosts your data +on MongoDB clusters. In this guide, you can learn how to get started with your +own free cluster. .. tip:: - For an additional example of how to build an application in Kotlin using - MongoDB Atlas and the {+driver-long+}, see the + To view another example that demonstrates how to build an + application in Kotlin that connects to MongoDB Atlas, see the :website:`Getting Started with the {+driver-long+} - ` developer tutorial. - -Consult the following steps to connect your Kotlin application with a MongoDB Atlas -cluster. + ` + developer tutorial. Set up Your Project ------------------- @@ -41,22 +46,24 @@ Set up Your Project Install Kotlin ~~~~~~~~~~~~~~ -Make sure that your system has Kotlin installed running on JDK 1.8 or later. +Make sure that your system has Kotlin installed and running on JDK 1.8 or later. For more information on getting started with Kotlin/JVM development, -refer to `Get started with Kotlin/JVM <{+kotlin-docs+}/jvm-get-started.html>`__ +refer to `Get started with Kotlin/JVM <{+kotlin-docs+}/docs/jvm-get-started.html>`__ in the Kotlin language documentation. Create the Project ~~~~~~~~~~~~~~~~~~~ -This guide shows you how to add the MongoDB Kotlin driver dependencies using -Gradle or Maven. We recommend that you use an integrated development -environment (IDE) such as Intellij IDEA or Eclipse IDE to make it more convenient -to configure Gradle or Maven to build and run your project. +This guide shows you how to add the MongoDB Kotlin driver dependencies +by using Gradle or Maven. We recommend that you use an integrated development +environment (IDE) such as IntelliJ IDEA or Eclipse IDE to configure +Gradle or Maven to build and run your project. -If you are not using an IDE, see -`Creating New Gradle Builds `_ -or `Building Maven `_ +If you are not using an IDE, see the +`Creating New Gradle Builds +`__ guide +or the `Building Maven +`__ guide for more information on how to set up your project. .. _add-mongodb-dependency: @@ -64,61 +71,95 @@ for more information on how to set up your project. Add MongoDB as a Dependency ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you are using `Gradle `__, add the following to your -``build.gradle.kts`` dependencies list: +If you are using `Gradle `__ to manage your +packages, add the following entry to your ``build.gradle.kts`` +dependencies list: .. include:: /includes/kotlin-driver-coroutine-gradle-versioned.rst -If you are using `Maven `__, add the following to -your ``pom.xml`` dependencies list: +If you are using `Maven `__ to manage your +packages, add the following entry to your ``pom.xml`` dependencies list: .. include:: /includes/kotlin-driver-coroutine-maven-versioned.rst -Once you configure your dependencies, ensure they are available to your -project which may require running your dependency manager and refreshing -the project in your IDE. +After you configure your dependencies, ensure that they are available to your +project by running the dependency manager and refreshing the +project in your IDE. + +Add Serialization Library Dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To enable the driver to convert between Kotlin objects and BSON, the +data format for documents in MongoDB, you must also add one or both of the +following serialization packages to your application: + +- ``bson-kotlinx`` *(Recommended)* +- ``bson-kotlin`` + +If you are using Gradle to manage your packages, add one of the following +entries to your ``build.gradle.kts`` dependencies list: + +.. include:: /includes/serialization-libs-gradle-versioned.rst + +If you are using Maven to manage your packages, add one of the following +entries to your ``pom.xml`` dependencies list: + +.. include:: /includes/serialization-libs-maven-versioned.rst + +After you configure your dependencies, ensure that they are available to your +project by running the dependency manager and refreshing the +project in your IDE. + +To learn more about these packages, see +:ref:`fundamentals-kotlin-serialization`. Create a MongoDB Cluster ------------------------ After setting up your Kotlin project dependencies, create a MongoDB cluster -where you can store and manage your data. Complete the -:atlas:`Get Started with Atlas ` guide +in which you can store and manage your data. Complete the +:atlas:`Get Started with Atlas ` tutorial to set up a new Atlas account, create and launch a free tier MongoDB cluster, -load datasets, and interact with the data. +and load sample datasets. -After completing the steps in the Atlas guide, you should have a new MongoDB -cluster deployed in Atlas, a new database user, and sample datasets loaded -into your cluster. +After you complete the steps in the Get Started with Atlas tutorial, you +have a new MongoDB cluster deployed in Atlas, a new database user, and +sample data loaded into your cluster. Connect to your Cluster ----------------------- -In this step, we create and run an application that uses the MongoDB Kotlin -driver to connect to your MongoDB cluster and run a query on the sample data. +This step shows how to create and run an application that uses the +{+driver-short+} to connect to your MongoDB cluster and run a query on +the sample data. -We pass instructions to the driver on how to connect to your -MongoDB cluster in a string called the *connection string*. This string -includes information on the hostname or IP address and port of your -cluster, authentication mechanism, user credentials when applicable, and -other connection options. +First, you must specify how the driver connects to your MongoDB cluster +by including a *connection string* in your code. This string includes +information on the hostname or IP address and port of your cluster, +authentication mechanism, user credentials, and other connection +options. -If you are connecting to an instance or cluster that is not hosted by Atlas, -see :ref:`Other Ways to Connect to MongoDB ` for +If you are connecting to an instance or cluster that is not hosted on Atlas, +see the :ref:`Other Ways to Connect to MongoDB +` section of the Connection Guide for instructions on how to format your connection string. To retrieve your connection string for the cluster and user you created in the previous step, log into your Atlas account and navigate to the -:guilabel:`Database` section and click the :guilabel:`Connect` button for the cluster that you -want to connect to as shown below. +:guilabel:`Database` page under Deployment and click the +:guilabel:`Connect` button for your cluster, which is shown in the following +image: .. figure:: /includes/figures/atlas_connection_select_cluster.png :alt: Atlas Connection GUI cluster selection screen -Proceed to the :guilabel:`Connect Your Application` step and select the Kotlin driver. -Select "4.10 or later" for the version. -Click the :guilabel:`Copy` icon to copy the *connection string* to your clipboard as -shown below. +Select the :guilabel:`Drivers` option for connection and select +:guilabel:`Kotlin` from the list of drivers and :guilabel:`4.10 or +later` from the version dropdown. + +Next, click the :guilabel:`Copy` icon, which is highlighted in the +following image, to copy your *connection string* to +your clipboard: .. figure:: /includes/figures/atlas_connection_copy_string_kotlin.png :alt: Atlas Connection GUI connection string screen @@ -129,20 +170,25 @@ for the next step. Query Your MongoDB Cluster from Your Application ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Next, create a file ``QuickStartDataClassExample.kt``. Use the following sample -code to run a query on your sample dataset in MongoDB Atlas, replacing the -value of the ``uri`` variable with your MongoDB Atlas connection string. -The example uses a Kotlin data class to model MongoDB data. +Next, create a file called ``QuickStartDataClassExample.kt`` in your +project. -Ensure you replace the "" section of the connection string with -the password you created for your user that has **atlasAdmin** permissions. +Copy the following sample code into the file and replace the value of +the ``uri`` variable with your MongoDB Atlas connection string that you +saved in the preceding step. Replace the ``""`` placeholder of +your connection string with the password you set for your user that has +**atlasAdmin** permissions: .. literalinclude:: /examples/generated/QuickStartDataClassExample.snippet.quick-start-data-class.kt :language: kotlin :caption: QuickStartDataClassExample.kt -When you run the ``main`` function, it should output the details -of the movie from the sample dataset which should look something like this: +.. note:: + + This example uses a Kotlin data class to model MongoDB data. + +When you run the ``main`` function, the application prints the details +of a movie document that matches the query, as shown in the following output: .. code-block:: none :copyable: false @@ -153,18 +199,19 @@ of the movie from the sample dataset which should look something like this: cast=[Michael J. Fox, Christopher Lloyd, Lea Thompson, Crispin Glover] ) -To learn more about using data classes to store and retrieve data, refer to -:ref:`Document Data Format: Data Classes `. +.. tip:: Data Classes + + To learn more about using data classes to store and retrieve data, + see the :ref:`fundamentals-data-classes` guide. -If you receive no output or an error, check whether you included the proper -connection string in your Kotlin class, and whether you loaded the sample dataset -into your MongoDB Atlas cluster. +If you don't see any output or receive an error, check whether you +included the proper connection string in your application. Also, confirm +that you successfully loaded the sample dataset into your MongoDB Atlas cluster. .. important:: Known connection issue when using TLS v1.3 - If you encounter an error connecting to your MongoDB instance or cluster - that resembles the following while running your application, you may need - to update your JDK to the latest patch release: + If you encounter the following error while connecting to your MongoDB + instance, you must update your JDK to the latest patch release: .. code-block:: none :copyable: false @@ -172,7 +219,8 @@ into your MongoDB Atlas cluster. javax.net.ssl.SSLHandshakeException: extension (5) should not be presented in certificate_request This exception is a known issue when using the TLS 1.3 protocol with - specific versions of JDK, but was fixed for the following releases: + specific versions of JDK, but this issue is fixed for the following + JDK versions: - JDK 11.0.7 - JDK 13.0.3 @@ -181,29 +229,28 @@ into your MongoDB Atlas cluster. To resolve this error, update your JDK to one of the preceding patch versions or a newer one. -After completing this step, you should have a working application that uses -the Kotlin driver to connect to your MongoDB cluster, run a query on the +After completing this step, you have a working application that uses +the {+driver-short+} to connect to your MongoDB cluster, run a query on the sample data, and print out the result. Working with the Document Class (Alternative) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the previous section, you ran a query on a sample collection to retrieve -data with a data class. In this section, you can learn to -use a `Document <{+api+}/apidocs/bson/org/bson/Document.html>`__ class +The preceding section demonstrates how to run a query on a sample +collection to retrieve data by using a Kotlin data class. This section +shows how to use the `Document <{+api+}/apidocs/bson/org/bson/Document.html>`__ class to store and retrieve data from MongoDB. -Next, create a new file to contain your application called ``QuickStartDocumentExample.kt`` -in the base package directory of your project. Use the following sample -code to run a query on your sample dataset in MongoDB Atlas, replacing the -value of the ``uri`` variable with your MongoDB Atlas connection string. +In a new file called ``QuickStartDocumentExample.kt``, paste the following sample +code to run a query on your sample dataset in MongoDB Atlas. Replace the +value of the ``uri`` variable with your MongoDB Atlas connection string: .. literalinclude:: /examples/generated/QuickStartDocumentExample.snippet.quick-start-document.kt :caption: QuickStartDocumentExample.kt :language: kotlin -When you run the ``main`` function, it should output the details -of the movie from the sample dataset which will look something like this: +When you run the ``main`` function, the application prints the details +of a movie document that matches the query, as shown in the following output: .. code-block:: json :copyable: false @@ -217,12 +264,13 @@ of the movie from the sample dataset which will look something like this: ... } -If you receive no output or an error, check whether you included the proper -connection string in your Kotlin class, and whether you loaded the sample dataset -into your MongoDB Atlas cluster. +If you don't see any output or receive an error, check whether you +included the proper connection string in your application. Also, confirm +that you successfully loaded the sample dataset into your MongoDB Atlas cluster. Next Steps ---------- -Learn how to read and modify data using the Kotlin driver in the :ref:`Fundamentals -CRUD guide `. +To learn more about the {+driver-short+}, see the +:ref:`kotlin-fundamentals-landing` guides, which describe relevant +concepts in detail and provide code examples for performing different tasks.