使用Mongo Scala驱动程序宏来读取带有其他嵌套字段的文档

时间:2017-06-19 10:05:28

标签: mongodb scala mongo-scala-driver

是否可以使用mongo-scala-driver macros从mongo db中读取包含案例类中指定字段的其他字段的文档?

我希望在反序列化时忽略案例类中但未在文档中指定的字段。但抛出异常。由于mongo db的模式较少,因此无法指定案例类中的总字段集。

我想要反序列化的文档看起来像这个json:

{
    "_id": 6,
    "nestedOne": {
        "nestedOneOne": 123,
        "nestedOneTwo": 456
    },
    "nestedTwo": {
        "nestedTwoOne": 789
    }
}

我希望以下最小的例子能够发挥作用:

import org.bson.codecs.configuration.CodecRegistries.{fromProviders, fromRegistries}
import org.bson.codecs.configuration.CodecRegistry
import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
import org.mongodb.scala.bson.codecs.Macros._
import org.mongodb.scala.model.Filters
import org.mongodb.scala.MongoClient
import org.mongodb.scala.bson.collection.immutable.Document
import scala.concurrent.Await

import scala.concurrent.duration._

// prepare the case classes and register them
case class TestDocument(_id: Int, nestedOne: Option[NestedOne])
case class NestedOne(nestedOneOne: Int, nestedOneTwo: Int)
val testCodecRegistry: CodecRegistry = fromRegistries(
  fromProviders(classOf[TestDocument], classOf[NestedOne]),
  DEFAULT_CODEC_REGISTRY
)

// prepare the test data & insert them
val testDocument = Document(
  "_id" -> 6,
  "nestedOne" -> Document("nestedOneOne" -> 123, "nestedOneTwo" -> 456),
  "nestedTwo" -> Document("nestedTwoOne" -> 789)
)

val mongoClient = MongoClient("mongodb://localhost:1234")
val database = mongoClient.getDatabase("testdatabase")
val testCollection = database.getCollection("test_collection").withCodecRegistry(testCodecRegistry)
Await.result(testCollection.insertOne(testDocument).toFuture, 2.minutes)

// try to read and deserialize the document again
val _ = Await.result(testCollection.find[TestDocument](Filters.equal("_id", 6)).toFuture(), 2.minutes)

但抛出以下异常:

head of empty list
java.util.NoSuchElementException: head of empty list
    at scala.collection.immutable.Nil$.head(List.scala:428)
    at scala.collection.immutable.Nil$.head(List.scala:425)
    at org.mongodb.scala.bson.codecs.macrocodecs.MacroCodec.readDocument(MacroCodec.scala:204)
    at org.mongodb.scala.bson.codecs.macrocodecs.MacroCodec.readDocument$(MacroCodec.scala:193)
    at de.peterschrott.mongotest.MongoTest$$anon$1$TestDocumentMacroCodec$3.readDocument(MongoTest.scala:29)
    at org.mongodb.scala.bson.codecs.macrocodecs.MacroCodec.readValue(MacroCodec.scala:173)
    at org.mongodb.scala.bson.codecs.macrocodecs.MacroCodec.readValue$(MacroCodec.scala:169)
    at de.peterschrott.mongotest.MongoTest$$anon$1$TestDocumentMacroCodec$3.readValue(MongoTest.scala:29)
    at org.mongodb.scala.bson.codecs.macrocodecs.MacroCodec.decode(MacroCodec.scala:104)
    at org.mongodb.scala.bson.codecs.macrocodecs.MacroCodec.decode$(MacroCodec.scala:96)
    at de.peterschrott.mongotest.MongoTest$$anon$1$TestDocumentMacroCodec$3.decode(MongoTest.scala:29)
    at com.mongodb.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)
    at com.mongodb.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:53)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
    at org.bson.codecs.configuration.LazyCodec.decode(LazyCodec.java:47)
    at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
    at com.mongodb.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:56)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
    at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
    at com.mongodb.connection.ReplyMessage.<init>(ReplyMessage.java:57)
    at com.mongodb.connection.CommandProtocol.getResponseDocument(CommandProtocol.java:139)
    at com.mongodb.connection.CommandProtocol.access$000(CommandProtocol.java:51)
    at com.mongodb.connection.CommandProtocol$CommandResultCallback.callCallback(CommandProtocol.java:271)
    at com.mongodb.connection.ResponseCallback.onResult(ResponseCallback.java:48)
    at com.mongodb.connection.ResponseCallback.onResult(ResponseCallback.java:23)
    at com.mongodb.connection.DefaultConnectionPool$PooledConnection$2.onResult(DefaultConnectionPool.java:470)
    at com.mongodb.connection.DefaultConnectionPool$PooledConnection$2.onResult(DefaultConnectionPool.java:464)
    at com.mongodb.connection.UsageTrackingInternalConnection$3.onResult(UsageTrackingInternalConnection.java:119)
    at com.mongodb.connection.UsageTrackingInternalConnection$3.onResult(UsageTrackingInternalConnection.java:115)
    at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
    at com.mongodb.connection.InternalStreamConnection.executeCallbackAndReceiveResponse(InternalStreamConnection.java:378)
    at com.mongodb.connection.InternalStreamConnection.access$1700(InternalStreamConnection.java:66)
    at com.mongodb.connection.InternalStreamConnection$ResponseBuffersCallback.onResult(InternalStreamConnection.java:420)
    at com.mongodb.connection.InternalStreamConnection$ResponseBuffersCallback.onResult(InternalStreamConnection.java:389)
    at com.mongodb.connection.InternalStreamConnection$ResponseHeaderCallback.onSuccess(InternalStreamConnection.java:562)
    at com.mongodb.connection.InternalStreamConnection$ResponseHeaderCallback.access$2200(InternalStreamConnection.java:517)
    at com.mongodb.connection.InternalStreamConnection$ResponseHeaderCallback$ResponseBodyCallback.onResult(InternalStreamConnection.java:584)
    at com.mongodb.connection.InternalStreamConnection$ResponseHeaderCallback$ResponseBodyCallback.onResult(InternalStreamConnection.java:568)
    at com.mongodb.connection.InternalStreamConnection$3.completed(InternalStreamConnection.java:447)
    at com.mongodb.connection.InternalStreamConnection$3.completed(InternalStreamConnection.java:444)
    at com.mongodb.connection.AsynchronousSocketChannelStream$BasicCompletionHandler.completed(AsynchronousSocketChannelStream.java:218)
    at com.mongodb.connection.AsynchronousSocketChannelStream$BasicCompletionHandler.completed(AsynchronousSocketChannelStream.java:201)
    at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
    at sun.nio.ch.Invoker.invokeDirect(Invoker.java:157)
    at sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:553)
    at sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:276)
    at sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
    at com.mongodb.connection.AsynchronousSocketChannelStream.readAsync(AsynchronousSocketChannelStream.java:125)
    at com.mongodb.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:444)
    at com.mongodb.connection.InternalStreamConnection.access$2000(InternalStreamConnection.java:66)
    at com.mongodb.connection.InternalStreamConnection$ResponseHeaderCallback.onResult(InternalStreamConnection.java:541)
    at com.mongodb.connection.InternalStreamConnection$ResponseHeaderCallback.onResult(InternalStreamConnection.java:517)
    at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
    at com.mongodb.connection.InternalStreamConnection$3.completed(InternalStreamConnection.java:447)
    at com.mongodb.connection.InternalStreamConnection$3.completed(InternalStreamConnection.java:444)
    at com.mongodb.connection.AsynchronousSocketChannelStream$BasicCompletionHandler.completed(AsynchronousSocketChannelStream.java:218)
    at com.mongodb.connection.AsynchronousSocketChannelStream$BasicCompletionHandler.completed(AsynchronousSocketChannelStream.java:201)
    at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
    at sun.nio.ch.UnixAsynchronousSocketChannelImpl.finishRead(UnixAsynchronousSocketChannelImpl.java:430)
    at sun.nio.ch.UnixAsynchronousSocketChannelImpl.finish(UnixAsynchronousSocketChannelImpl.java:191)
    at sun.nio.ch.UnixAsynchronousSocketChannelImpl.onEvent(UnixAsynchronousSocketChannelImpl.java:213)
    at sun.nio.ch.KQueuePort$EventHandlerTask.run(KQueuePort.java:301)
    at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

有没有办法解决已解决的问题?

1 个答案:

答案 0 :(得分:1)

问题是由于不同的数据类型:

case class TestDocument(_id: Long, nestedOne: Option[NestedOne])
case class NestedOne(nestedOneOne: Int, nestedOneTwo: Int)
val testCodecRegistry: CodecRegistry = fromRegistries(
  fromProviders(classOf[TestDocument], classOf[NestedOne]),
  DEFAULT_CODEC_REGISTRY
)

具有以下数据形状:

Document("_id" -> 6L,
         "nestedOne" -> Document("nestedOneOne" -> 1, "nestedOneTwo" -> 2))

您正在插入此数据形状:

Document(
  "_id" -> 6L,
  "nestedOne" -> List(Document("nestedOneOne" -> 123)),
  "nestedTwo" -> List(Document("nestedTwoOne" -> 789))
)

所以结果是错误,我添加了SCALA-319来改善在这种情况下引发的错误。