Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
MongoDBchevron-right

Introdução ao MongoDB Kotlin Driver

Mohit Sharma9 min read • Published Sep 09, 2024 • Updated Sep 09, 2024
MongoDBKotlin
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Alguns recursos mencionados abaixo serão descontinuados em 30, 2025 de setembro. Saiba mais.
Este é um artigo introdutório sobre como criar um aplicativo no Kotlin usando o MongoDB Atlas e o driver do MongoDB Kotlin, a adição mais recente à nossa lista de drivers oficiais. Juntos, criaremos um aplicativo CRUD que abrange os fundamentos de como usar o MongoDB como banco de dados, enquanto aproveitamos os benefícios do Kotlin como linguagem de programação, como classes de dados, corrotinas e fluxo.

Pré-requisitos

Este é um artigo de introdução. Portanto, não é necessário muito como pré-requisito, mas a familiaridade com o Kotlin como linguagem de programação será útil.
Além disso, precisamos de uma conta do Atlas, que é gratuita para sempre. Crie uma conta, caso ainda não tenha. Isso fornece o MongoDB como um banco de dados em nuvem e muito mais. Mais adiante neste tutorial, usaremos essa conta para criar um novo cluster, carregar um conjunto de dados e, por fim, consultá-lo.
Em geral, o MongoDB é um banco de dados de documentos distribuído e multiplataforma que permite criar aplicativos com esquema flexível. Caso você não esteja familiarizado com ele ou queira fazer uma rápida recapitulação, recomendamos explorar a série MongoDB Jumpstart para se familiarizar com o MongoDB e seus vários serviços em menos 10 minutos. Ou, se preferir ler, siga nosso guia.
E, por último, para ajudar em nossas atividades de desenvolvimento, usaremos o Jetbrains IntelliJ IDEA (Community Edition), que tem suporte padrão para a linguagem Kotlin.

Driver MongoDB Kotlin vs MongoDB Realm Kotlin SDK

Antes de começarmos, gostaria de falar um pouco sobre o Realm Kotlin SDK, um dos SDKs usados para criar aplicações móveis do lado do cliente usando o ecossistema MongoDB. Ele não deve ser confundido com o driver MongoDB Kotlin para programação do lado do servidor. O driver MongoDB Kotlin, um driver de linguagem, permite que você interaja perfeitamente com o Atlas, um banco de dados em nuvem, com os benefícios do paradigma da linguagem Kotlin. É apropriado para criar aplicações de back-end, scripts, etc.
Para tornar o aprendizado mais significativo e prático, criaremos um aplicativo CRUD. Confira nosso repositório do Github se quiser acompanhar. Então, vamos começar.

Criar um projeto

Para criar o projeto, podemos usar o assistente de projeto, que pode ser encontrado nas opções de menu File. Em seguida, selecione New, seguido de Project. Isso abrirá a tela New Project, conforme mostrado abaixo, e atualizará o projeto e a linguagem para Kotlin.
Assistente de projeto
Após a sincronização inicial do Gradle, nosso projeto está pronto para ser executado. Então, vamos tentar usar o ícone de execução na barra de menu ou simplesmente pressionar CRTL + R no Mac. Atualmente, nosso projeto não faz muito além de imprimir Hello World! e os argumentos fornecidos, mas a mensagem BUILD SUCCESSFUL no console de execução é o que estamos procurando, o que nos informa que a configuração do projeto está concluída.
desenvolver sucesso
Agora, a próxima etapa é adicionar o driver Kotlin ao nosso projeto, o que nos permite interagir com o MongoDB Atlas.

Adicionando o driver Kotlin do MongoDB

Adicionar o driver ao projeto é simples e direto. Basta atualizar o bloco dependencies com a dependência do driver Kotlin no arquivo de criação — ou seja, build.gradle.
1dependencies {
2 // Kotlin coroutine dependency
3 implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
4
5 // MongoDB Kotlin driver dependency
6 implementation("org.mongodb:mongodb-driver-kotlin-coroutine:4.10.1")
7}
E agora estamos prontos para nos conectar ao MongoDB Atlas usando o driver Kotlin.

Conectando-se ao banco de dados

Para se conectar ao banco de dados, primeiro precisamos do Connection URI que pode ser encontrado pressionando connect to cluster em nossa conta Atlas, conforme mostrado abaixo.
Imagem
Para obter mais detalhes, você também pode consultar nossa documentação.
Com o URI de conexão disponível, a próxima etapa é criar um arquivo Kotlin. Setup.kt é onde gravamos o código para conexão com o MongoDB Atlas.
Arquivo Setup.kt
A conexão com o nosso banco de dados pode ser feita em duas etapas. Primeiro, criamos uma instância do MongoClient usando Connection URI.
1val connectionString = "mongodb+srv://<username>:<enter your password>@cluster0.sq3aiau.mongodb.net/?retryWrites=true&w=majority"
2val client = MongoClient.create(connectionString = connectString)
Depois, use o cliente para se conectar ao banco de dados, sample_restaurants, um conjunto de dados de amostra para restaurantes. Um conjunto de dados de amostra é uma ótima maneira de explorar a plataforma e criar um POC mais realista para validar suas ideias. Para saber como propagar seu primeiro banco de dados Atlas com dados de amostra, visite a documentação.
1val databaseName = "sample_restaurants"
2val db: MongoDatabase = client.getDatabase(databaseName = databaseName)
A codificação connectionString não é uma boa abordagem e pode levar a riscos de segurança ou à incapacidade de fornecer acesso baseado em função. Para evitar esses problemas e seguir as melhores práticas, usaremos variáveis de ambiente. Outras abordagens comuns são o uso do Vault, variáveis de configuração de compilação e variáveis de ambiente de CI/CD.
Para adicionar variáveis de ambiente, use Modify run configuration, que pode ser encontrado clicando com o botão direito do mouse no arquivo.
adicionar uma variável de ambiente
Juntamente com o código para acessar a variável de ambiente, nosso código final tem a seguinte aparência.
1suspend fun setupConnection(
2 databaseName: String = "sample_restaurants",
3 connectionEnvVariable: String = "MONGODB_URI"
4): MongoDatabase? {
5 val connectString = if (System.getenv(connectionEnvVariable) != null) {
6 System.getenv(connectionEnvVariable)
7 } else {
8 "mongodb+srv://<usename>:<password>@cluster0.sq3aiau.mongodb.net/?retryWrites=true&w=majority"
9 }
10
11 val client = MongoClient.create(connectionString = connectString)
12 val database = client.getDatabase(databaseName = databaseName)
13
14 return try {
15 // Send a ping to confirm a successful connection
16 val command = Document("ping", BsonInt64(1))
17 database.runCommand(command)
18 println("Pinged your deployment. You successfully connected to MongoDB!")
19 database
20 } catch (me: MongoException) {
21 System.err.println(me)
22 null
23 }
24}
No trecho de código acima, ainda podemos usar uma string codificada. Isso é feito apenas para fins de demonstração, permitindo que você use um URI de conexão diretamente para facilitar e executar isso por meio de qualquer editor on-line. Mas é altamente recomendável evitar a codificação de um URI de conexão.
Com a função setupConnection pronta, vamos testá-la e realizar a query do banco de dados para obter a contagem e o nome da coleção.
1suspend fun listAllCollection(database: MongoDatabase) {
2
3 val count = database.listCollectionNames().count()
4 println("Collection count $count")
5
6 print("Collection in this database are -----------> ")
7 database.listCollectionNames().collect { print(" $it") }
8}
Ao executar esse código, nosso resultado fica assim:
listar resultado da coleção
Até agora, você deve ter notado que estamos usando a palavra-chave suspend com listAllCollection(). listCollectionNames() é uma função assíncrona, pois interage com o banco de dados e, portanto, idealmente seria executada em uma thread diferente. E como o driver Kotlin do MongoDB oferece suporte ao Coroutines, o paradigma de linguagem assíncrona, nativo do Kotlin, podemos nos beneficiar dele usando funções suspend.
Da mesma forma, para descartar coleções, usamos a função suspend.
1suspend fun dropCollection(database: MongoDatabase) {
2 database.getCollection<Objects>(collectionName = "restaurants").drop()
3}
Com isso concluído, estamos prontos para começar a trabalhar em nosso aplicativo CRUD. Portanto, para começar, precisamos criar uma classe data que represente as informações do restaurante que nosso aplicativo salva no banco de dados.
1data class Restaurant(
2 @BsonId
3 val id: ObjectId,
4 val address: Address,
5 val borough: String,
6 val cuisine: String,
7 val grades: List<Grade>,
8 val name: String,
9 @BsonProperty("restaurant_id")
10 val restaurantId: String
11)
12
13data class Address(
14 val building: String,
15 val street: String,
16 val zipcode: String,
17 val coord: List<Double>
18)
19
20data class Grade(
21 val date: LocalDateTime,
22 val grade: String,
23 val score: Int
24)
No trecho de código acima, usamos duas anotações:
  1. @BsonId, que representa a identidade exclusiva ou _id de um documento.
  2. @BsonProperty, que cria um alias para chaves no documento – por exemplo, restaurantId representa restaurant_id.
Observação: nossa classe Restaurant aqui é uma réplica exata de um documento de restaurante no conjunto de dados de exemplo, mas alguns campos podem ser ignorados ou marcados como opcionais - por exemplo, grades e address - enquanto mantém a capacidade de executar operações CRUD. Podemos fazer isso, pois o document model do MongoDB permite um esquema flexível para nossos dados.

criar

Com todo o trabalho pesado feito (10 linhas de código para conexão), adicionar um novo documento ao banco de dados é realmente simples e pode ser feito com uma linha de código usando insertOne. Então, vamos criar um novo arquivo chamado Create.kt, que conterá todas as operações de criação.
1suspend fun addItem(database: MongoDatabase) {
2
3 val collection = database.getCollection<Restaurant>(collectionName = "restaurants")
4 val item = Restaurant(
5 id = ObjectId(),
6 address = Address(
7 building = "Building", street = "street", zipcode = "zipcode", coord =
8 listOf(Random.nextDouble(), Random.nextDouble())
9 ),
10 borough = "borough",
11 cuisine = "cuisine",
12 grades = listOf(
13 Grade(
14 date = LocalDateTime.now(),
15 grade = "A",
16 score = Random.nextInt()
17 )
18 ),
19 name = "name",
20 restaurantId = "restaurantId"
21 )
22
23 collection.insertOne(item).also {
24 println("Item added with id - ${it.insertedId}")
25 }
26}
Quando o executamos, a saída no console é:
insertOne
Reitero, não se esqueça de adicionar uma variável de ambiente novamente para este arquivo, se você teve problemas ao executá-lo.
Se quisermos adicionar vários documento à coleção, podemos usar insertMany, que é recomendado em vez da execução de insertOne em um loop.
1suspend fun addItems(database: MongoDatabase) {
2 val collection = database.getCollection<Restaurant>(collectionName = "restaurants")
3 val newRestaurants = collection.find<Restaurant>().first().run {
4 listOf(
5 this.copy(
6 id = ObjectId(), name = "Insert Many Restaurant first", restaurantId = Random
7 .nextInt().toString()
8 ),
9 this.copy(
10 id = ObjectId(), name = "Insert Many Restaurant second", restaurantId = Random
11 .nextInt().toString()
12 )
13 )
14 }
15
16 collection.insertMany(newRestaurants).also {
17 println("Total items added ${it.insertedIds.size}")
18 }
19}
Inserir muitas saídas
Com esses resultados no console, podemos dizer que os dados foram adicionados com sucesso.
Mas e se quisermos ver o objeto no banco de dados? Uma maneira é com uma operação de leitura, que faríamos em breve ou usaríamos o MongoDB Compass para visualizar as informações.
O MongoDB Compass é uma ferramenta GUI interativa e gratuita para consultar, otimizar e analisar os dados do MongoDB em seu sistema. Para começar, baixe a ferramenta e use connectionString para se conectar ao banco de dados.
MongoDB Compass

Leia

Para ler as informações do banco de dados, podemos usar o operador find. Vamos começar lendo qualquer documento.
1val collection = database.getCollection<Restaurant>(collectionName = "restaurants")
2collection.find<Restaurant>().limit(1).collect {
3 println(it)
4}
O operador find retorna uma lista de resultados, mas como estamos interessados apenas em um único documento, podemos usar o operador limit para limitar nosso conjunto de resultados. Nesse caso, seria um único documento.
Se estendermos isso ainda mais e quisermos ler um documento específico, poderemos adicionar parâmetros de filtro sobre ele:
1val queryParams = Filters
2 .and(
3 listOf(
4 eq("cuisine", "American"),
5 eq("borough", "Queens")
6 )
7 )
Ou podemos usar qualquer um dos operadores da nossa lista. O código final tem a seguinte aparência.
1suspend fun readSpecificDocument(database: MongoDatabase) {
2 val collection = database.getCollection<Restaurant>(collectionName = "restaurants")
3 val queryParams = Filters
4 .and(
5 listOf(
6 eq("cuisine", "American"),
7 eq("borough", "Queens")
8 )
9 )
10
11
12 collection
13 .find<Restaurant>(queryParams)
14 .limit(2)
15 .collect {
16 println(it)
17 }
18
19}
Para a saída, vemos isso:
ler saída de documento específico
Não se esqueça de adicionar a variável de ambiente novamente para este arquivo, se você teve problemas ao executá-lo.
Outro caso de uso prático que vem com uma operação de leitura é a paginação aos resultados. Isso pode ser feito com os operadores limit e offset.
1suspend fun readWithPaging(database: MongoDatabase, offset: Int, pageSize: Int) {
2 val collection = database.getCollection<Restaurant>(collectionName = "restaurants")
3 val queryParams = Filters
4 .and(
5 listOf(
6 eq(Restaurant::cuisine.name, "American"),
7 eq(Restaurant::borough.name, "Queens")
8 )
9 )
10
11 collection
12 .find<Restaurant>(queryParams)
13 .limit(pageSize)
14 .skip(offset)
15 .collect {
16 println(it)
17 }
18}
Mas com essa abordagem, frequentemente, o tempo de resposta da query aumenta com o valor do offset. Para superar isso, podemos nos beneficiar criando um Index, como mostrado abaixo.
1val collection = database.getCollection<Restaurant>(collectionName = "restaurants")
2val options = IndexOptions().apply {
3 this.name("restaurant_id_index")
4 this.background(true)
5}
6
7collection.createIndex(
8 keys = Indexes.ascending("restaurant_id"),
9 options = options
10)

Atualização

Agora, vamos discutir como editar/atualizar um documento existente. Novamente, vamos criar rapidamente um novo arquivo Kotlin, Update.Kt.
Em geral, há duas maneiras de atualizar qualquer documento:
  • Execute uma operação update, o que nos permite atualizar campos específicos dos documentos correspondentes sem afetar os outros campos.
  • Execute uma operação replace para substituir o documento correspondente pelo novo documento.
Para este exercício, usaremos o documento que criamos anteriormente com a operação create {restaurant_id: "restaurantId"} e atualizaremos restaurant_id com um valor mais realista. Vamos dividir isso em duas subtarefas para maior clareza.
Primeiro, usando Filters, executamos uma query para filtrar o documento, semelhante à operação de leitura anterior.
1val collection = db.getCollection<Restaurant>("restaurants")
2val queryParam = Filters.eq("restaurant_id", "restaurantId")
Então, podemos definir o restaurant_id com um valor inteiro aleatório usando Updates.
1val updateParams = Updates.set("restaurant_id", Random.nextInt().toString())
E, finalmente, usamos updateOne para atualizar o documento em uma operação atômica.
1collection.updateOne(filter = queryParam, update = updateParams).also {
2 println("Total docs modified ${it.matchedCount} and fields modified ${it.modifiedCount}")
3}
No exemplo acima, já sabíamos qual documento queríamos atualizar – o restaurante com id restauratantId – mas poderia haver casos de uso em que essa não seria a situação. Nesses casos, primeiro procuraríamos o documento e depois o atualizaríamos. findOneAndUpdate pode ser útil. Ele permite combinar esses dois processos em uma operação atômica, desbloqueando desempenho adicional.
Outra variação do mesmo pode ser atualizar vários documentos com uma chamada. updateMany é útil para esses casos de uso - por exemplo, se quisermos atualizar o cuisine de todos os restaurantes para seu tipo favorito de culinária e borough para o Brooklyn.
1suspend fun updateMultipleDocuments(db: MongoDatabase) {
2 val collection = db.getCollection<Restaurant>("restaurants")
3 val queryParam = Filters.eq(Restaurant::cuisine.name, "Chinese")
4 val updateParams = Updates.combine(
5 Updates.set(Restaurant::cuisine.name, "Indian"),
6 Updates.set(Restaurant::borough.name, "Brooklyn")
7 )
8
9 collection.updateMany(filter = queryParam, update = updateParams).also {
10 println("Total docs matched ${it.matchedCount} and modified ${it.modifiedCount}")
11 }
12}
Nestes exemplos, usamos set e combine com Updates. Mas há muitos outros tipos de operador de atualização a serem analisados que nos permitem realizar muitas operações intuitivas, como definir currentDate ou o registro de data e hora, aumentar ou diminuir o valor do campo e assim por diante. Para saber mais sobre os diferentes tipos de operadores de atualização que você pode executar com Kotlin e MongoDB, consulte nossos documentos.

Excluir

Agora, vamos explorar uma última operação CRUD: excluir. Começaremos explorando como excluir um único documento. Para fazer isso, usaremos findOneAndDelete em vez de deleteOne. Como benefício adicional, isso também retorna o documento excluído como saída. Em nosso exemplo, excluímos o restaurante:
1val collection = db.getCollection<Restaurant>(collectionName = "restaurants")
2val queryParams = Filters.eq("restaurant_id", "restaurantId")
3
4collection.findOneAndDelete(filter = queryParams).also {
5 it?.let {
6 println(it)
7 }
8}
excluir saída
Para excluir vários documentos, podemos usar deleteMany. Podemos, por exemplo, usar isso para excluir todos os dados que criamos anteriormente com nossa operação de criação.
1suspend fun deleteRestaurants(db: MongoDatabase) {
2 val collection = db.getCollection<Restaurant>(collectionName = "restaurants")
3
4 val queryParams = Filters.or(
5 listOf(
6 Filters.regex(Restaurant::name.name, Pattern.compile("^Insert")),
7 Filters.regex("restaurant_id", Pattern.compile("^restaurant"))
8 )
9 )
10 collection.deleteMany(filter = queryParams).also {
11 println("Document deleted : ${it.deletedCount}")
12 }
13}

Resumo

Parabéns! Agora você sabe configurar seu primeiro aplicativo Kotlin com MongoDB e executar operações CRUD. O código-fonte completo do aplicativo pode ser encontrado no GitHub.
Se você tiver algum feedback sobre sua experiência de trabalho com o driver MongoDB Kotlin, envie um comentário em nosso portal de feedback do usuário ou entre em contato conosco no Twitter: @codeWithMohit.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Artigo

7 coisas que aprendi ao modelar dados para as estatísticas do YouTube


Oct 01, 2024 | 13 min read
Início rápido

Pipelines de agregação complexos com Baunilha PHP e MongoDB


Sep 05, 2024 | 10 min read
Tutorial

Crie uma Java REST API com Quarkus e Eclipse JNoSQL para MongoDB


Jan 30, 2024 | 6 min read
Artigo

Java vs Kotlin: Different Syntax, Same Possibilities


Nov 25, 2024 | 5 min read
Sumário