简体   繁体   English

ktor 中的 BsonInvalidOperationException

[英]BsonInvalidOperationException in ktor

Being new to MongoDB, I'm currently integrating the kMongo library to my ktor project, and trying to create a database to read & write event models to.作为 MongoDB 的新手,我目前正在将kMongo库集成到我的 ktor 项目中,并尝试创建一个数据库来读取和写入事件模型。

Following the instructions for object mapping in the kMongo user manual , I've created a mongoId field which gets serialised as a String named _id .按照kMongo 用户手册中 object 映射的说明,我创建了一个mongoId字段,它被序列化为一个名为_idString

My event model is a data class, nested in sealed classes but gets serialised correctly by KotlinX-Serialization.我的事件 model 是数据 class,嵌套在密封类中,但通过 KotlinX-Serialization 正确序列化。 The model looks as such: model 看起来是这样的:

sealed class Event {
    @SerialName("_id") abstract val mongoId: String
    abstract val id: ID.Event
    abstract val dateTime: LocalDateTime

    fun asString() = id.toString()

    sealed class Hiring : Event() {
        @SerialName("_id") abstract override val mongoId: String
        abstract override val id: ID.Event
        abstract override val dateTime: LocalDateTime

        @Serializable
        data class Start(
            override val id: ID.Event,
            override val dateTime: LocalDateTime,
            val hiringDetailsId: ID.HiringDetails
        ) : Hiring() {
            @SerialName("_id") override val mongoId: String = id.asString()
        }
        ...

In a repository class, I initialise MongoDB and use the generic, parameter-less find() on a collection to retrieve all Event models from the database:在存储库 class 中,我初始化 MongoDB 并在集合上使用通用的无参数find()从数据库中检索所有Event模型:

    ...
    private val kmongo = KMongo.createClient().coroutine.client
    private val db = kmongo.getDatabase("test")
    private val eventCollection = db.getCollection<Event>().coroutine
    ...
    override suspend fun getAllEvents() = eventCollection.find().toList()

Then inside of the Main class, I try to load the Event data on a click trigger:然后在 Main class 内部,我尝试在点击触发器上加载Event数据:

...
val id = ID.Event(UUID())
...
it.on.click {
   runBlocking {
      val events = eventRepo.getAllEvents().toString()
      logger.debug { events }
   }
}

The strange part starts here, the server starts correctly and MongoDB is initialised correctly, but as soon as I try to do the read on the click trigger, I am presented with following error:奇怪的部分从这里开始,服务器正确启动并且 MongoDB 正确初始化,但是一旦我尝试在点击触发器上进行读取,我就会收到以下错误:

org.bson.BsonInvalidOperationException: readString can only be called when CurrentBSONType is STRING, not when CurrentBSONType is DOCUMENT.
    at org.bson.AbstractBsonReader.verifyBSONType(AbstractBsonReader.java:689)
    at org.bson.AbstractBsonReader.checkPreconditions(AbstractBsonReader.java:721)
    at org.bson.AbstractBsonReader.readString(AbstractBsonReader.java:456)
    at com.github.jershell.kbson.FlexibleDecoder.decodeString(BsonFlexibleDecoder.kt:130)
    at kotlinx.serialization.encoding.AbstractDecoder.decodeStringElement(AbstractDecoder.kt:58)
    at kotlinx.serialization.internal.AbstractPolymorphicSerializer.deserialize(AbstractPolymorphicSerializer.kt:52)
    at kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:257)
    at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:16)
    at org.litote.kmongo.serialization.SerializationCodec.decode(SerializationCodec.kt:66)
    at com.mongodb.internal.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)
    at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:60)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:87)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
    at org.bson.internal.LazyCodec.decode(LazyCodec.java:48)
    at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:104)
    at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:63)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:87)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
    at com.mongodb.internal.connection.ReplyMessage.<init>(ReplyMessage.java:51)
    at com.mongodb.internal.connection.InternalStreamConnection.getCommandResult(InternalStreamConnection.java:535)
    at com.mongodb.internal.connection.InternalStreamConnection.access$500(InternalStreamConnection.java:86)
    at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:520)
    at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:498)
    at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:821)
    at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:785)
    at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:645)
    at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:642)
    at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:250)
    at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:233)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:129)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:160)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:573)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:276)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
    at com.mongodb.internal.connection.AsynchronousSocketChannelStream$AsynchronousSocketChannelAdapter.read(AsynchronousSocketChannelStream.java:144)
    at com.mongodb.internal.connection.AsynchronousChannelStream.readAsync(AsynchronousChannelStream.java:118)
    at com.mongodb.internal.connection.AsynchronousChannelStream.readAsync(AsynchronousChannelStream.java:107)
    at com.mongodb.internal.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:642)
    at com.mongodb.internal.connection.InternalStreamConnection.access$600(InternalStreamConnection.java:86)
    at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:775)
    at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:760)
    at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:645)
    at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:642)
    at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:250)
    at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:233)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:129)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finishRead(UnixAsynchronousSocketChannelImpl.java:447)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finish(UnixAsynchronousSocketChannelImpl.java:195)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.onEvent(UnixAsynchronousSocketChannelImpl.java:217)
    at java.base/sun.nio.ch.KQueuePort$EventHandlerTask.run(KQueuePort.java:312)
    at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:113)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

According to the stacktrace, something seems to go wrong in the BSON filtering part, despite there being none.根据堆栈跟踪, BSON过滤部分似乎有 go 错误,尽管没有。 When I use the MongoDB compass to validate the object inside of the database, I can see that everything is initialised and written perfectly fine:当我使用 MongoDB 指南针验证数据库内部的 object 时,我可以看到一切都已初始化并且写得非常好:

MongoDB 指南针

The normal id field is used in my software internally as an ID.Event object type whilst the _id is used by Mongo internally.正常的id字段在我的软件内部用作ID.Event object 类型,而_idMongo在内部使用。

Can someone point me to what the potential issue could be here?有人可以指出这里可能存在的潜在问题吗?

I'm not familiar with Kotlin, but I'd like to dive into this a bit further:我不熟悉 Kotlin,但我想更深入地了解一下:

If it wouldn't unwrap the second time, the Mongo Compass would likely reveal the _id or id field to contain a bracket { while these are currently mapped as expected (a String for _id and an object for id ).如果它不会第二次展开,Mongo Compass 可能会显示_idid字段以包含括号{而这些当前已按预期映射( String用于_id和 object 用于id )。

To confirm, the current structure of your document is (eg here in the playground ):确认一下,您文档的当前结构是(例如在操场上):

{
  _id: "7d51",
  id: {
    id: "7d51"
  },
  hiringDetailsId: {
    id: "8392"
  }
}

We can see that in your screenshot from Compass where the _id field shows the value being the string directly whereas the other two fields show that the values are Objects (that each contain { id: "<string>" } values).我们可以在 Compass 的屏幕截图中看到,其中_id字段直接显示值是字符串,而其他两个字段显示值是对象(每个对象都包含{ id: "<string>" }值)。

The error is specifically stating that the code is expecting a string but finding a document:该错误特别指出代码需要一个字符串但找到了一个文档:

BsonInvalidOperationException: readString can only be called when CurrentBSONType is STRING, not when CurrentBSONType is DOCUMENT.

I can't speak to the internal unpacking, but it really feels to me like the nested id.id (and potentially also hiringDetailsId.id ) is the problem here.我不能谈论内部拆包,但我真的觉得嵌套的id.id (也可能是hiringDetailsId.id )是这里的问题。 Even if it isn't directly related, it would seem to be an opportunity to simplify the schema unless there is a compelling reason to introduce that extra level of nesting.即使它不直接相关,它似乎也是一个简化架构的机会,除非有令人信服的理由引入额外的嵌套级别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM