https://kotlinlang.org logo
Join SlackCommunities
Powered by
# kmongo
  • a

    acoconut

    01/18/2022, 3:31 PM
    Hi! Probably a very silly question:
    Copy code
    [ERROR] /Users/acoconut/.m2/repository/org/litote/kmongo/kmongo-core/4.4.0/kmongo-core-4.4.0.jar!/META-INF/kmongo-core.kotlin_module: (-1, -1) Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is 1.4.2.
    Does this mean that kmongo was compiled with 1.6.0 and that I’m using a lower version of kotlin (which I should be) that is not compatible OR does it mean that I have some other kind of version mess in my local?
    • 1
    • 1
  • t

    Tomas Kormanak

    02/11/2022, 2:51 PM
    Hi, I need to register custom serializer module to KMnogo serializer, but I cant find a way how to do it. I am using
    kotlinx.serialization
    It is mentioned in docs, but I can't get it, Does someone have a code snippet with example?
    r
    h
    • 3
    • 2
  • r

    rocketraman

    02/17/2022, 3:00 AM
    Trying to save
    Point
    (GeoJSON) data using kotlinx-serialization... I see Mongo has a
    com.mongodb.client.model.geojson.Point
    type, but kmongo doesn't recognize it.
    • 1
    • 1
  • r

    rocketraman

    03/12/2022, 12:04 AM
    I store a sealed class with two possible subtypes in a collection. When using typed queries, I can validate the type using the discriminator as part of the query, but is it possible to coerce the type in the query to give me access to the subtype properties? Or am I stuck with using query strings?
    • 1
    • 1
  • a

    André Martins

    03/25/2022, 2:41 PM
    Hello is it possible to do a bulk upsert using Kmongo?
    • 1
    • 3
  • t

    tim

    04/07/2022, 10:28 AM
    Hello, is it possible to not have defaults encoded when inserting a documents (I’m using kotlinx.serialization)? For example given:
    Copy code
    data class Foo(val name: String, val other: String? = null)
    val thing = Foo("bar")
    ...
    insert(thing)
    The document in mongo is
    {"name": "bar", "other": null}
    when I want it to be
    {"name":"bar"}
    . Alternatively, can I provide my own Json instance to kmongo? Thanks!
  • q

    Qverkk

    04/17/2022, 3:29 PM
    Hey @tim have you gotten LocalDate serialization with kotlinx.serialization and kmongo coroutines? I see there's a default implementation for LocalDate serialization but it doesn't seem to work
    t
    • 2
    • 2
  • q

    Qverkk

    04/17/2022, 3:31 PM
    Copy code
    java.lang.ClassCastException: class kotlinx.serialization.json.internal.StreamingJsonEncoder cannot be cast to class com.github.jershell.kbson.BsonEncoder (kotlinx.serialization.json.internal.StreamingJsonEncoder and com.github.jershell.kbson.BsonEncoder are in unnamed module of loader 'app')
  • a

    André Martins

    04/19/2022, 10:14 AM
    Hello, I’m doing an
    insertMany
    query and trying to use an upsert although there is no InsertManyOption for upsert I came up with the following but this is very inefficient, is there any other way to insert and ignore duplicates?
    Copy code
    myCollection.bulkWrite(
        *customers.map {
            updateOne<Customer>(
                Customer::id eq it.id,
                KMongoUtil.toBsonModifier(it, UpdateConfiguration.updateOnlyNotNullProperties),
                upsert()
            )
        }.toTypedArray()
    )
    • 1
    • 1
  • a

    André Martins

    04/22/2022, 12:17 PM
    Hey is there anyway to mock a
    CoroutineFindPublisher<T>
    ? Some
    TestCoroutineFindPublisher<T>
    like it exists for the reactive publisher
  • t

    Tomas Kormanak

    04/29/2022, 11:33 AM
    Hi, I use KMongo with kotlinx.serialization and I have aproblem with serialization kotlinx.datetime objects as they are saved to mongo as strings. Am I missing some config?
  • i

    IsaacMart

    06/16/2022, 2:19 PM
    Hello team, am new to mongodb and am using it for my ktor project. How can i return the inserted document back to client after insertion. I need the doc to store it in room
    s
    • 2
    • 5
  • r

    Ryunos

    10/12/2022, 2:18 PM
    Hi, I’m trying to build a sort BSON to give to my find request from a string, representing my path to the property in my collection’s class. Do you know how I could do it? I managed to do it when the properties are not nested but it’s trickier when I’m trying to access a property of one of my class properties...
    Copy code
    fun <E : Any> SortProperty.toSortBson(kClass: KClass<E>): Bson {
        val kProperty = kClass.memberProperties.find { it.name == this.property }
            ?: throw InvalidSortPropertyException(this.property, kClass.simpleName)
    
        return if (this.direction == SortDirection.ASC) {
            ascending(kProperty)
        } else {
            descending(kProperty)
        }
    }
  • j

    jean

    10/13/2022, 2:15 PM
    I added
    org.litote.kmongo:kmongo-coroutine-serialization:4.7.1
    as a dependency and I’m trying to count the documents in a collection with this
    Copy code
    val collection = database.getCollection(collectionName, Document::class.java)
    collection.countDocuments()
    But this gives me a
    Publisher<T>
    but I was expecting this to be a
    suspend
    function. How am I supposed to use this?
  • i

    IsaacMart

    11/03/2022, 9:48 AM
    I have a data class of Tasker which has an embedded list of skills from data class named Skill. I want to querry list of taskers based on category_skill which is found inside a skill that the tasker possess.i have tried couple of solution below but which work on the mongo playground but can't work in ktor. Bellow are the data classes.
    r
    • 2
    • 3
  • s

    Stephen

    02/09/2023, 2:10 PM
    Hi guys, does anyone know of an example somewhere with kmongo and GridFS? Ive found an example using GridFSBucket.uploadFromStream but uploadFromPublisher seems to be the available method for the reactivestreams lib. thanks.
  • s

    Stephen

    02/10/2023, 7:35 AM
    Hello again, I'm trying to add a unique index but getting an error. Tried this code........ val users = db.getCollection<User>().createIndex(User::email, indexOptions = IndexOptions().unique(true)) but it doesn't like it. 😞
    r
    • 2
    • 2
  • r

    ribesg

    02/15/2023, 2:06 PM
    What is the state of KMongo? The latest release states:
    Copy code
    This version should be the last release in the KMongo repo (if no critical bug found).
    A MR is planned to move the code into the MongoDB repository :champagne::clinking_glasses:
    That's cool and all but where can we get an ETA? Is there an official MongoDB issue we can follow? I'm stuck on KMongo 4.7.2 because the Java Mongo Driver has issue on version 4.8.0, which KMongo depends on. Now it has been fixed in subsequent 4.8.x patches, but KMongo was not updated. I could use some Gradle black magic to use KMongo 4.8.0 with Mongo 4.8.x but I'm kinda against that. Now the Java Mongo Driver has been updated to 4.9.0 with a bunch of fixes and features. What do we do?
    👀 3
    • 1
    • 1
  • m

    Mark Vogel

    02/17/2023, 12:46 AM
    I'm attempting to use Kotlinx Serialization with KMongo and I can't seem to get the serialization to work properly; It does insert the data, but completely ignores all of the Kotlinx annotations. I see that, on the KMongo Website I'm supposed to create a custom
    Json
    configuration, but I can't seem to find any mention of where to use that
    Json
    configuration. The closest I see is the reference to registerModule and registerSerializer, but I can't find those functions anywhere either. I've included a screenshot of all the dependencies I have. Note these are all from:
    Copy code
    implementation("org.litote.kmongo:kmongo-id-serialization:$kMongoVersion")
    implementation("org.litote.kmongo:kmongo-coroutine-serialization:$kMongoVersion")
    If someone could point me in the right direction I would appreciate it very much! 🙂
    c
    • 2
    • 8
  • j

    Jorge Bo

    07/21/2023, 5:36 PM
    Hey, i’m trying to understand how kmongo deals with connection timeout or server down errors, i’m using kmongo with coroutines. Everytime there is a timeout or the db is down i’m not being informed about the error and thet server keeps stuck waiting. How should i deal with it?
  • c

    CLOVIS

    07/31/2023, 7:59 AM
    KMongo is officially deprecated in favor of the official MongoDB driver. Thanks to the team for the amazing library, I hope we can have similar syntax for the official driver.
    👀 2
  • t

    Tomas Kormanak

    10/05/2023, 1:50 PM
    Hi, I am working on migration from KMongo to MongoDb Kotlin driver and we would like to keep using kmongo-id for now. But I can't find a way how to setup serializers within the driver and I am getting this error:
    Copy code
    Class 'StringId' is not registered for polymorphic serialization in the scope of 'Id'
    Any idea?
    g
    • 2
    • 3
  • a

    Ashni Mehta

    11/05/2023, 6:05 PM
    Hi folks, I'm a Product Manager at MongoDB! We released the Kotlin driver a few months ago, and we'd love to hear some feedback -- if you've migrated from kmongo to the official driver, any pain points, etc. Feel free to chime in via 🧵!
    c
    m
    • 3
    • 7
  • c

    CLOVIS

    11/20/2024, 11:27 PM
    Welcome everyone! It is time for me to start showing what I've been working on for the past 6 months. As you know, KMongo has been deprecated after the release of the official Kotlin driver. However, many projects haven't migrated to the official driver, since it lacks most of the syntax that made KMongo enjoyable in the first place. KtMongo (cat-mongo) takes inspiration from the ideas behind KMongo, but rethinks everything from the bottom up, based on the official Kotlin driver. Based on our 4+ years of experience using KMongo in production, we have discovered many common patterns that are verbose to write or are easy to mess up. For these patterns, we have added (or are planning to add) new alternative options to avoid these issues. Let's take a look at a few requests:
    Copy code
    users.find {
        User::pets / Pet::name eq "Bob"
    }
    As you can see, a DSL replaces the parenthesis, but the syntax is almost identical.
    Copy code
    measurements.upsertOne(
        filter = {
            Measurement::room eq 5
            Measurement::storey eq 2
        },
        update = {
            Measurement::creationDate setOnInsert Instant.now()
            Measurement::lastModifiedDate set Instant.now()
            Measurement::value inc 12
        }
    )
    The DSL vastly simplifies syntax: no need to remember to group update operators, no need to specify
    and
    when multiple filters are specified—and we can finally use a regular
    if
    inside requests to create complex queries without making the code complex itself. Currently, KtMongo has released its 0.4.0 version. It isn't stable yet, and won't be for a while, but it is ready for feedback and early tests. Currently, it supports: • insertOne, insertMany • updateOne, updateMany, upsertOne • bulkWrite • find • count • drop as well as the operators: • $eq, $gt, $gte, $in, $lt, $lte, $ne, $and, $not, $or, $exists, $type, $all, $elemMatch • $inc, $rename, $set, $setOnInsert, $unset, $.0. Want to learn more reasons why to migrate when the library becomes stable? Visit our website. We plan on adding documentation pages on gradual migration (migrating from KMongo to KtMongo one-file-at-a-time, without a big-bang migration). Join us to discuss the project in #C078Z1QRHL3 , we're excited to see how far we can push Kotlin and MongoDB!
    👍 2
    m
    • 2
    • 2
  • i

    IsaacMart

    11/25/2024, 3:35 PM
    Hello team. I have built my server using ktor and mongo db. Being a novice at mongoDb i haven't quite leveraged on mongo db aggregation and lookups for optimization. I need assistance in changing my function to using aggregation but i a experiencing an error. This is what i currently work with
    Copy code
    Then current function
    override suspend fun getRequest(requestId: String): Request? {
        val requestDto = requestsDto.findOneById(id = requestId) ?: return null
    
        // Here we get the client details as AuthRequest
        val client = users.findOneById(requestDto.user_id) ?: return null
    
        val clientDetails = AuthRequest(
            user_id = requestDto.user_id,
            first_name = client.first_name ?: "",
            last_name = client.last_name ?: "",
            phone_number = client.phone_number ?: "",
            isPhone_number_verified = client.isPhone_number_verified,
            address = client.address ?: "",
            gender = client.gender ?: "",
            email = client.email ?: "",
            role = client.role ?: "",
            withdrawStatus = client.withdrawStatus ?: "",
            walletId = client.walletId ?: "",
            walletBalance = client.walletBalance ?: 0.0,
            mySecuredAmount = client.mySecuredAmount ?: 0.0,
            referralId = client.referralId ?: "",
            isFirstTimeRequesting = client.isFirstTimeRequesting,
            verified_identity_url = client.verified_identity_url ?: "",
            verification_level1_status = client.verification_level1_status,
            verification_level2_status = client.verification_level2_status,
            verification_level3_status = client.verification_level3_status,
            verification_level4_status = client.verification_level4_status,
            verification_level5_status = client.verification_level5_status,
            profile_url = client.profile_url ?: "",
            client_average_rating = client.client_average_rating ?: 0.0,
            client_complete_tasks = client.client_complete_tasks ?: 0,
            isTasker = client.isTasker,
            tasker_application_status = client.tasker_application_status,
            latitude = client.latitude ?: 0.0,
            longitude = client.longitude ?: 0.0,
            password = "",
        )
    
        // Here we fetch the details of the tasker from our user documents
        val taskerClient = users.findOneById(requestDto.tasker_id) ?: return null
    
        val taskerClientDetails = AuthRequest(
            user_id = requestDto.tasker_id,
            first_name = taskerClient.first_name ?: "",
            last_name = taskerClient.last_name ?: "",
            phone_number = taskerClient.phone_number ?: "",
            isPhone_number_verified = taskerClient.isPhone_number_verified,
            address = taskerClient.address ?: "",
            gender = taskerClient.gender ?: "",
            email = taskerClient.email ?: "",
            role = taskerClient.role ?: "",
            withdrawStatus = taskerClient.withdrawStatus ?: "",
            walletId = taskerClient.walletId ?: "",
            walletBalance = taskerClient.walletBalance ?: 0.0,
            mySecuredAmount = taskerClient.mySecuredAmount ?: 0.0,
            referralId = taskerClient.referralId ?: "",
            isFirstTimeRequesting = taskerClient.isFirstTimeRequesting,
            verified_identity_url = taskerClient.verified_identity_url ?: "",
            verification_level1_status = taskerClient.verification_level1_status,
            verification_level2_status = taskerClient.verification_level2_status,
            verification_level3_status = taskerClient.verification_level3_status,
            verification_level4_status = taskerClient.verification_level4_status,
            verification_level5_status = taskerClient.verification_level5_status,
            profile_url = taskerClient.profile_url ?: "",
            client_average_rating = taskerClient.client_average_rating ?: 0.0,
            client_complete_tasks = taskerClient.client_complete_tasks ?: 0,
            isTasker = taskerClient.isTasker,
            tasker_application_status = taskerClient.tasker_application_status,
            latitude = taskerClient.latitude ?: 0.0,
            longitude = taskerClient.longitude ?: 0.0,
            password = "",
        )
    
        // Here we fetch the tasker details from the Mongo collection
        val taskerDto = taskersDto.findOneById(requestDto.tasker_id) ?: return null
        val tasker = Tasker(
            tasker_id = requestDto.tasker_id,
            user = taskerClientDetails,
            job_images = taskerDto.job_images ?: emptyList(),
            is_approved = taskerDto.is_approved,
            is_accepting_requests = taskerDto.is_accepting_requests,
            tasker_reg_date = taskerDto.tasker_reg_date,
            is_favorite = taskerDto.is_favorite,
            taskerCancelledTasks = taskerDto.taskerCancelledTasks,
            tasker_average_rating = taskerDto.tasker_average_rating ?: 0.0,
            respond_time = taskerDto.respond_time ?: "",
            tasker_complete_tasks = taskerDto.tasker_complete_tasks ?: 0,
            tasker_about = taskerDto.tasker_about ?: "",
            passport_photo = taskerDto.passport_photo ?: "",
            id_card_front = taskerDto.id_card_front ?: "",
            id_card_back = taskerDto.id_card_back ?: "",
            distance = taskerDto.distance ?: 0.0
        )
    
        return Request(
            request_id = requestDto.request_id,
            user = clientDetails,
            tasker = tasker,
            requested_skill = requestDto.requested_skill ?: "",
            scheduled_date = requestDto.scheduled_date ?: "",
            scheduled_time = requestDto.scheduled_time ?: "",
            task_location = requestDto.task_location ?: "",
            task_description = requestDto.task_description ?: "",
            task_distance = requestDto.task_distance ?: 0.0,
            date_of_request = requestDto.date_of_request ?: 0,
            task_images = requestDto.task_images ?: emptyList(),
            notification_status = requestDto.notification_status ?: "",
            date_of_task_notification = requestDto.date_of_task_notification ?: 0,
            receipt_no = requestDto.receipt_no ?: "",
            isNotificationSeenByClient = requestDto.isNotificationSeenByClient,
            isNotificationSeenByTasker = requestDto.isNotificationSeenByTasker,
            task_latitude = requestDto.task_latitude ?: 0.0,
            task_longitude = requestDto.task_longitude ?: 0.0,
        )
    }
    Copy code
    // This is my aggregated function that I need assistance with. It currently has an error and i can't figure it out.
    
    override suspend fun getRequest(requestId: String): Request? {
    
        // Define the aggregation pipeline
              val pipeline = listOf(
                // Match the request by requestId
                match(eq("_id", requestId)),
    
            // Lookup client details from the users collection
            lookup(
                from = "users",
                localField = "user_id",
                foreignField = "_id",
                newAs = "client"
            ),
            // Unwind the client array
            unwind("\$client"),
    
            // Lookup tasker details from the users collection
            lookup(
                from = "users",
                localField = "tasker_id",
                foreignField = "_id",
                newAs = "tasker_user"
            ),
            // Unwind the tasker_user array
            unwind("\$tasker_user"),
    
            // Lookup tasker metadata from the taskers collection
            lookup(
                from = "taskers",
                localField = "tasker_id",
                foreignField = "_id",
                newAs = "tasker_metadata"
            ),
            // Unwind the tasker_metadata array
            unwind("\$tasker_metadata"),
    
            // Project the required fields
            project(
                fields(
                    Request::request_id from RequestDTO::request_id,
                    Request::user from "\$client",
                    Request::tasker from mapOf(
                        Tasker::tasker_id to "\$tasker_metadata._id",
    
                        Tasker::user to "\$tasker_user",
                        Tasker::job_images to "\$tasker_metadata.job_images",
                        Tasker::is_approved to "\$tasker_metadata.is_approved",
                        Tasker::is_accepting_requests to "\$tasker_metadata.is_accepting_requests",
                        Tasker::tasker_reg_date to "\$tasker_metadata.tasker_reg_date",
                        Tasker::is_favorite to "\$tasker_metadata.is_favorite",
                        Tasker::taskerCancelledTasks to "\$tasker_metadata.taskerCancelledTasks",
                        Tasker::tasker_average_rating to "\$tasker_metadata.tasker_average_rating",
                        Tasker::respond_time to "\$tasker_metadata.respond_time",
                        Tasker::tasker_complete_tasks to "\$tasker_metadata.tasker_complete_tasks",
                        Tasker::tasker_about to "\$tasker_metadata.tasker_about",
                        Tasker::passport_photo to "\$tasker_metadata.passport_photo",
                        Tasker::id_card_front to "\$tasker_metadata.id_card_front",
                        Tasker::id_card_back to "\$tasker_metadata.id_card_back",
                        Tasker::distance to "\$tasker_metadata.distance",
                    ),
                    Request::requested_skill from RequestDTO::requested_skill,
                    Request::scheduled_date from RequestDTO::scheduled_date,
                    Request::scheduled_time from RequestDTO::scheduled_time,
                    Request::task_location from RequestDTO::task_location,
                    Request::task_description from RequestDTO::task_description,
                    Request::task_distance from RequestDTO::task_distance,
                    Request::date_of_request from RequestDTO::date_of_request,
                    Request::task_images from RequestDTO::task_images,
                    Request::notification_status from RequestDTO::notification_status,
                    Request::date_of_task_notification from RequestDTO::date_of_task_notification,
                    Request::receipt_no from RequestDTO::receipt_no,
                    Request::isNotificationSeenByClient from RequestDTO::isNotificationSeenByClient,
                    Request::isNotificationSeenByTasker from RequestDTO::isNotificationSeenByTasker,
                    Request::task_latitude from RequestDTO::task_latitude,
                    Request::task_longitude from RequestDTO::task_longitude
                )
            )
        )
    
        // Execute the aggregation pipeline
        return requestsDto.aggregate<Request>(pipeline).first()
    }
    
    The request module
    
    @Serializable
    data class Request(
        @BsonId
        val request_id: String = ObjectId().toString(), // Document_id
    
        val user: AuthRequest,
        val tasker: Tasker,
        val requested_skill: String,
        val scheduled_date: String,
        val scheduled_time: String,
        val task_location: String,
        val task_description: String,
        val task_distance: Double,
        val date_of_request: Long,
        val task_images : List<String>,
        val notification_status: String,  // Pending, Declined, Accepted, Expired, Completed $ Canceled
        val date_of_task_notification: Long, // Declined, Accepted, Expired Date, Completed $ Canceled
        val receipt_no: String,
        val isNotificationSeenByClient: Boolean,
        val isNotificationSeenByTasker: Boolean,
        val task_latitude: Double,
        val task_longitude: Double
    
    )
  • k

    kurt_steiner

    11/27/2024, 2:10 PM
    hey, guys, I meet a problem about mongodb, there is no problem with insert, but the
    findMany
    method, I don't know how to fix it, can you help me out ?
    Copy code
    fun findMany(name: String? = null, age: Int? = null): List<User> {
            val queryParams = mutableListOf<Bson>()
    
            if (name != null) {
                queryParams.add(Filters.eq(User::name.name, name))
            }
    
            if (age != null) {
                queryParams.add(Filters.eq(User::age.name, age))
            }
    
            return users.find(Filters.and(queryParams)).toList()
        }
    c
    • 2
    • 1
  • k

    kurt_steiner

    11/27/2024, 2:10 PM
    UserCodec.kt,User.kt
    UserCodec.ktUser.kt
  • c

    CLOVIS

    01/14/2025, 8:00 AM
    KtMongo 0.6.0 is out and adds helpers to handle
    Map<String, V>
    more easily: •
    Map.get()
    •
    Map.isMapEmpty()
    •
    Map.isMapNotEmpty()
    https://opensavvy.gitlab.io/ktmongo/docs • #C078Z1QRHL3
    s
    • 2
    • 1
  • c

    CLOVIS

    02/03/2025, 8:00 AM
    KtMongo 0.8.0 is out, which adds support for simple aggregation pipelines! Aggregation pipelines allow querying data in more complex ways than regular request. At the moment, few stages are supported, don't hesitate to request new ones.
    Copy code
    collection.aggregate()
        .match { User::role eq Role.Player }
        .skip(30)
        .limit(20)
        .toList()
    In this version, KtMongo also gains support for update pipelines, allowing to use some pipeline operations to update data:
    Copy code
    collection.updateManyWithPipeline {
        set {
            User::isPlayer set (of(User::role) eq of(Role.Player))
        }
    }
    Additionally, this documentation adds a dedicated documentation page to filtered operators:
    Copy code
    collection.find {
        Invoice::paidAt gteNotNull criteria.minPaidAt
    }
    as well as filtered collections, which are convenient for logical deletion:
    Copy code
    val drafts = collection.filter {
        Invoice::status eq Status.Draft
    }
    
    drafts.find()
    drafts.updateMany { Draft::age inc 1 }
    https://opensavvy.gitlab.io/ktmongo/docs
    🙌 2
  • c

    CLOVIS

    03/03/2025, 8:00 AM
    KtMongo 0.12.0 is out, which adds support for array aggregation updates. Which do you prefer, Kotlin?
    Copy code
    users().aggregate()
    	.project {
    		include(User::name)
    		User::bestPassingGrades set User::grades
    			.filter { it gt of(50) }
    			.map { it / Grade::value }
    			.sortedDescending()
    			.take(of(3))
    	}
    	.sort { ascending(User::name) }
    	.limit(2)
    Or BSON?
    Copy code
    [
    	{
    		"$project": {
    			"name": 1,
    			"bestPassingGrades": {
    				"$firstN": {
    					"input": {
    						"$sortArray": {
    							"input": {
    								"$map": {
    									"input": {
    										"$filter": {
    											"input": "$grades",
    											"as": "this",
    											"cond": {"$gt": ["$$this", {"$literal": 50}]}
    										}
    									},
    									"as": "this",
    									"in": {"$getField": {"input": "$$this", "field": "value"}}
    								}
    							},
    							"sortBy": -1
    						}
    					},
    					"n": {"$literal": 3}
    				}
    			}
    		}
    	},
    	{"$sort": {"name": 1}},
    	{"$limit": 2}
    ]
    If you're in Bordeaux, France, I'm giving a talk on the KtMongo project, its current limitations, and how it can be adopted in a KMongo project, in two weeks. You can sign up for free here. If you use aggregation pipelines, I am searching for users who use temporary variables within their pipelines to discuss how KtMongo could help. Please get in touch. https://opensavvy.gitlab.io/ktmongo/docs/news/2025/03/01/v0.12.0.html