acoconut
01/18/2022, 3:31 PM[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?Tomas Kormanak
02/11/2022, 2:51 PMkotlinx.serialization
It is mentioned in docs, but I can't get it, Does someone have a code snippet with example?rocketraman
02/17/2022, 3:00 AMPoint
(GeoJSON) data using kotlinx-serialization... I see Mongo has a com.mongodb.client.model.geojson.Point
type, but kmongo doesn't recognize it.rocketraman
03/12/2022, 12:04 AMAndré Martins
03/25/2022, 2:41 PMtim
04/07/2022, 10:28 AMdata 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!Qverkk
04/17/2022, 3:29 PMQverkk
04/17/2022, 3:31 PMjava.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')
André Martins
04/19/2022, 10:14 AMinsertMany
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?
myCollection.bulkWrite(
*customers.map {
updateOne<Customer>(
Customer::id eq it.id,
KMongoUtil.toBsonModifier(it, UpdateConfiguration.updateOnlyNotNullProperties),
upsert()
)
}.toTypedArray()
)
André Martins
04/22/2022, 12:17 PMCoroutineFindPublisher<T>
? Some TestCoroutineFindPublisher<T>
like it exists for the reactive publisherTomas Kormanak
04/29/2022, 11:33 AMIsaacMart
06/16/2022, 2:19 PMRyunos
10/12/2022, 2:18 PMfun <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)
}
}
jean
10/13/2022, 2:15 PMorg.litote.kmongo:kmongo-coroutine-serialization:4.7.1
as a dependency and I’m trying to count the documents in a collection with this
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?IsaacMart
11/03/2022, 9:48 AMStephen
02/09/2023, 2:10 PMStephen
02/10/2023, 7:35 AMribesg
02/15/2023, 2:06 PMThis 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?Mark Vogel
02/17/2023, 12:46 AMJson
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:
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! 🙂Jorge Bo
07/21/2023, 5:36 PMCLOVIS
07/31/2023, 7:59 AMTomas Kormanak
10/05/2023, 1:50 PMClass 'StringId' is not registered for polymorphic serialization in the scope of 'Id'
Any idea?Ashni Mehta
11/05/2023, 6:05 PMCLOVIS
11/20/2024, 11:27 PMusers.find {
User::pets / Pet::name eq "Bob"
}
As you can see, a DSL replaces the parenthesis, but the syntax is almost identical.
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!IsaacMart
11/25/2024, 3:35 PMThen 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,
)
}
// 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
)
kurt_steiner
11/27/2024, 2:10 PMfindMany
method, I don't know how to fix it, can you help me out ?
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()
}
kurt_steiner
11/27/2024, 2:10 PMCLOVIS
01/14/2025, 8:00 AMMap<String, V>
more easily:
• Map.get()
• Map.isMapEmpty()
• Map.isMapNotEmpty()
https://opensavvy.gitlab.io/ktmongo/docs • #C078Z1QRHL3CLOVIS
02/03/2025, 8:00 AMcollection.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:
collection.updateManyWithPipeline {
set {
User::isPlayer set (of(User::role) eq of(Role.Player))
}
}
Additionally, this documentation adds a dedicated documentation page to filtered operators:
collection.find {
Invoice::paidAt gteNotNull criteria.minPaidAt
}
as well as filtered collections, which are convenient for logical deletion:
val drafts = collection.filter {
Invoice::status eq Status.Draft
}
drafts.find()
drafts.updateMany { Draft::age inc 1 }
https://opensavvy.gitlab.io/ktmongo/docsCLOVIS
03/03/2025, 8:00 AMusers().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?
[
{
"$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