Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

MongoDB Developer
Atlas
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Productschevron-right
Atlaschevron-right

Serverless Development with Kotlin, AWS Lambda, and MongoDB Atlas

Nic Raboy6 min read • Published Aug 01, 2023 • Updated Aug 01, 2023
ServerlessKotlinAtlas
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
As seen in a previous tutorial, creating a serverless function for AWS Lambda with Java and MongoDB isn't too complicated of a task. In fact, you can get it done with around 35 lines of code!
However, maybe your stack doesn't consist of Java, but instead Kotlin. What needs to be done to use Kotlin for AWS Lambda and MongoDB development? The good news is not much will be different!
In this tutorial, we'll see how to create a simple AWS Lambda function. It will use Kotlin as the programming language and it will use the MongoDB Kotlin driver for interacting with MongoDB.

The requirements

There are a few prerequisites that must be met in order to be successful with this particular tutorial:
  • Must have a Kotlin development environment installed and configured on your local computer.
  • Must have a MongoDB Atlas instance deployed and configured.
  • Must have an Amazon Web Services (AWS) account.
The easiest way to develop with Kotlin is through IntelliJ, but it is a matter of preference. The requirement is that you can build Kotlin applications with Gradle.
For the purpose of this tutorial, any MongoDB Atlas instance will be sufficient whether it be the M0 free tier, the serverless pay-per-use tier, or something else. However, you will need to have the instance properly configured with user rules and network access rules. If you need help, use our MongoDB Atlas tutorial as a starting point.

Defining the project dependencies with the Gradle Kotlin DSL

Assuming you have a project created using your tooling of choice, we need to properly configure the build.gradle.kts file with the correct dependencies for AWS Lambda with MongoDB.
In the build.gradle.kts file, include the following:
1import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2
3plugins {
4 kotlin("jvm") version "1.9.0"
5 application
6 id("com.github.johnrengelman.shadow") version "7.1.2"
7}
8
9application {
10 mainClass.set("example.Handler")
11}
12
13group = "org.example"
14version = "1.0-SNAPSHOT"
15
16repositories {
17 mavenCentral()
18}
19
20dependencies {
21 testImplementation(kotlin("test"))
22 implementation("com.amazonaws:aws-lambda-java-core:1.2.2")
23 implementation("com.amazonaws:aws-lambda-java-events:3.11.1")
24 implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1")
25 implementation("org.mongodb:bson:4.10.2")
26 implementation("org.mongodb:mongodb-driver-kotlin-sync:4.10.2")
27}
28
29tasks.test {
30 useJUnitPlatform()
31}
32
33tasks.withType<KotlinCompile> {
34 kotlinOptions.jvmTarget = "1.8"
35}
There are a few noteworthy items in the above configuration.
Looking at the plugins first, you'll notice the use of Shadow:
1plugins {
2 kotlin("jvm") version "1.9.0"
3 application
4 id("com.github.johnrengelman.shadow") version "7.1.2"
5}
AWS Lambda expects a ZIP or a JAR. By using the Shadow plugin, we can use Gradle to build a "fat" JAR, which includes both the application and all required dependencies. When using Shadow, the main class must be defined.
To define the main class, we have the following:
1application {
2 mainClass.set("example.Handler")
3}
The above assumes that all our code will exist in a Handler class in an example package. Yours does not need to match, but note that this particular class and package will be referenced throughout the tutorial. You should swap names wherever necessary.
The next item to note is the dependencies block:
1dependencies {
2 testImplementation(kotlin("test"))
3 implementation("com.amazonaws:aws-lambda-java-core:1.2.2")
4 implementation("com.amazonaws:aws-lambda-java-events:3.11.1")
5 implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1")
6 implementation("org.mongodb:bson:4.10.2")
7 implementation("org.mongodb:mongodb-driver-kotlin-sync:4.10.2")
8}
In the above block, we are including the various AWS Lambda SDK packages as well as the MongoDB Kotlin driver. These dependencies will allow us to use MongoDB with Kotlin and AWS Lambda.
If you wanted to, you could run the following command:
1./gradlew shadowJar
As long as the main class exists, it should build a JAR file for you.

Developing a serverless function with Kotlin and MongoDB

With the configuration items out of the way, we can focus on the development of our serverless function. Open the project's src/main/kotlin/example/Handler.kt file and include the following boilerplate code:
1package example
2
3import com.amazonaws.services.lambda.runtime.Context
4import com.amazonaws.services.lambda.runtime.RequestHandler
5import com.mongodb.client.model.Filters
6import com.mongodb.kotlin.client.MongoClient
7import com.mongodb.kotlin.client.MongoCollection
8import com.mongodb.kotlin.client.MongoDatabase
9import org.bson.Document
10import org.bson.conversions.Bson
11import org.bson.BsonDocument
12
13class Handler : RequestHandler<Map<String, String>, Void> {
14
15 override fun handleRequest(input: Map<String, String>, context: Context): void {
16
17 return null;
18
19 }
20}
The above code won't do much of anything if you tried to execute it on AWS Lambda, but it is a starting point. Let's start by establishing a connection to MongoDB.
Within the Handler class, add the following:
1class Handler : RequestHandler<Map<String, String>, Void> {
2
3 private val mongoClient: MongoClient = MongoClient.create(System.getenv("MONGODB_ATLAS_URI"))
4
5 override fun handleRequest(input: Map<String, String>, context: Context): void {
6
7 val database: MongoDatabase = mongoClient.getDatabase("sample_mflix")
8 val collection: MongoCollection<Document> = database.getCollection("movies")
9
10 return null;
11
12 }
13}
First, you'll notice that we are creating a mongoClient variable to hold the information about our connection. This client will be created using a MongoDB Atlas URI that we plan to store as an environment variable. It is strongly recommended that you use environment variables to store this information so your credentials don't get added to your version control.
In case you're unsure what the MongoDB Atlas URI looks like, it looks like the following:
1mongodb+srv://<username>:<password>@<clustername>.dmhrr.mongodb.net/?retryWrites=true&w=majority
You can find your exact connection string using the MongoDB Atlas CLI or through the MongoDB Atlas dashboard.
Within the handleRequest function, we get a reference to the database and collection that we want to use:
1val database: MongoDatabase = mongoClient.getDatabase("sample_mflix")
2val collection: MongoCollection<Document> = database.getCollection("movies")
For this particular example, we are using the sample_mflix database and the movies collection, both of which are part of the optional MongoDB Atlas sample dataset. Feel free to use a database and collection that you already have.
Now we can focus on interactions with MongoDB. Make a few changes to the Handler class so it looks like this:
1package example
2
3import com.amazonaws.services.lambda.runtime.Context
4import com.amazonaws.services.lambda.runtime.RequestHandler
5import com.mongodb.client.model.Filters
6import com.mongodb.kotlin.client.MongoClient
7import com.mongodb.kotlin.client.MongoCollection
8import com.mongodb.kotlin.client.MongoDatabase
9import org.bson.Document
10import org.bson.conversions.Bson
11import org.bson.BsonDocument
12
13class Handler : RequestHandler<Map<String, String>, List<Document>> {
14
15 private val mongoClient: MongoClient = MongoClient.create(System.getenv("MONGODB_ATLAS_URI"))
16
17 override fun handleRequest(input: Map<String, String>, context: Context): List<Document> {
18
19 val database: MongoDatabase = mongoClient.getDatabase("sample_mflix")
20 val collection: MongoCollection<Document> = database.getCollection("movies")
21
22 var filter: Bson = BsonDocument()
23
24 if(input.containsKey("title") && !input.get("title").isNullOrEmpty()) {
25 filter = Filters.eq("title", input.get("title"))
26 }
27
28 val results: List<Document> = collection.find(filter).limit(5).toList()
29
30 return results;
31
32 }
33}
Instead of using Void in the RequestHandler and void as the return type for the handleRequest function, we are now using List<Document> because we plan to return an array of documents to the requesting client.
This brings us to the following:
1var filter: Bson = BsonDocument()
2
3if(input.containsKey("title") && !input.get("title").isNullOrEmpty()) {
4 filter = Filters.eq("title", input.get("title"))
5}
6
7val results: List<Document> = collection.find(filter).limit(5).toList()
8
9return results;
Instead of executing a fixed query when the function is invoked, we are accepting input from the user. If the user provides a title field with the invocation, we construct a filter for it. In other words, we will be looking for movies with a title that matches the user input. If no title is provided, we just query for all documents in the collection.
For the actual find operation, rather than risking the return of more than a thousand documents, we are limiting the result set to five and are converting the response from a cursor to a list.
At this point in time, our simple AWS Lambda function is complete. We can focus on the building and deployment of the function now.

Building and deploying a Kotlin function to AWS Lambda

Before we worry about AWS Lambda, let's build the project using Shadow. From the command line, IntelliJ, or with whatever tool you're using, execute the following:
1./gradlew shadowJar
Find the JAR file, which is probably in the build/libs directory unless you specified otherwise.
Everything we do next will be done in the AWS portal. There are three main items that we want to take care of during this process:
  1. Add the environment variable with the MongoDB Atlas URI to the Lambda function.
  2. Rename the "Handler" information in Lambda to reflect the actual project.
  3. Upload the JAR file to AWS Lambda.
Within the AWS Lambda dashboard for your function, click the "Configuration" tab followed by the "Environment Variables" navigation item. Add MONGODB_ATLAS_URI along with the appropriate connection string when prompted. Make sure the connection string reflects your instance with the proper username and password.
You can now upload the JAR file from the "Code" tab of the AWS Lambda dashboard. When this is done, we need to tell AWS Lambda what the main class is and the function that should be executed.
In the "Code" tab, look for "Runtime Settings" and choose to edit it. In our example, we had example as the package and Handler as the class. We also had our function logic in the handleRequest function.
With all this in mind, change the "Handler" within AWS Lambda to example.Handler::handleRequest or whatever makes sense for your project.
At this point, you should be able to test your function.
On the "Test" tab of the AWS Lambda dashboard, choose to run a test as is. You should get a maximum of five results back. Next, try using the following input criteria:
1{
2 "title": "The Terminator"
3}
Your response will now look different because of the filter.

Conclusion

Congratulations! You created your first AWS Lambda function in Kotlin and that function supports communication with MongoDB!
While this example was intended to be short and simple, you could add significantly more logic to your functions that engage with other functionality of MongoDB, such as aggregations and more.
If you'd like to see how to use Java to accomplish the same thing, check out my previous tutorial on the subject titled Serverless Development with AWS Lambda and MongoDB Atlas Using Java.

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Getting started with MongoDB Atlas Search and Java


Jul 30, 2024 | 7 min read
Tutorial

​​Reinventing Multi-modal Search With MongoDB and Anyscale


Sep 18, 2024 | 20 min read
Tutorial

Building AI Graphs With Rivet and MongoDB Atlas Vector Search to Power AI Applications


Sep 18, 2024 | 10 min read
Tutorial

Launch a Fully Managed RAG Workflow With MongoDB Atlas and Amazon Bedrock


May 08, 2024 | 6 min read
Table of Contents