【问题标题】:Scala error: org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class scala.SomeScala 错误:org.bson.codecs.configuration.CodecConfigurationException:找不到类 scala.Some 的编解码器
【发布时间】:2017-07-04 05:35:24
【问题描述】:

我正在尝试获取 mongo 查询结果的计数,但出现错误 org.bson.codecs.configuration.CodecConfigurationException:找不到类 scala.Some 的编解码器。有人可以帮忙吗?

这是我的代码:

def fetchData() = {
    val mongoClient = MongoClient("mongodb://127.0.0.1")
    val database = mongoClient.getDatabase("assignment")
    val movieCollection = database.getCollection("movies")
    val ratingCollection = database.getCollection("ratings")
    val latch1 = new CountDownLatch(1)
    movieCollection.find().subscribe(new Observer[Document] {

      override def onError(e: Throwable): Unit = {
        println("Error while fetching data")
        e.printStackTrace()
      }

      override def onComplete(): Unit = {
        latch1.countDown()
        println("Completed fetching data")
      }

      override def onNext(movie: Document): Unit = {
        if (movie.get("movieId") != null) {
          ratingCollection.count(equal("movieId", movie.get("movieId"))).subscribe(new Observer[Long] {
            override def onError(e: Throwable): Unit = println(s"onError: $e")
            override def onNext(result: Long): Unit = { println(s"In count result : $result") }
            override def onComplete(): Unit = println("onComplete")
          })
        }
      }

    })
    latch1.await()
    mongoClient.close()
  }

我正在使用 mongo 3.2.12 和 scala -driver:

<dependency>
  <groupId>org.mongodb.scala</groupId>
  <artifactId>mongo-scala-driver_2.11</artifactId>
  <version>2.1.0</version>
</dependency>

【问题讨论】:

    标签: mongodb scala


    【解决方案1】:

    这个答案有点老了,在解决同样的问题浪费了很多小时后,我写了一个更新

    现在使用宏要容易得多:

    import org.mongodb.scala.bson.codecs._
    
      val movieCodecProvider: CodecProvider = Macros.createCodecProviderIgnoreNone[Movie]()
      val codecRegistry: CodecRegistry = fromRegistries(fromProviders(movieCodecProvider), DEFAULT_CODEC_REGISTRY)
    
      val movieCollection: MongoCollection[Movie] = mongo.database.withCodecRegistry(codecRegistry).getCollection("movie_collection")
    

    在编写“手动”查询(即不解析整个 Movie 对象的查询,例如更新)时请注意,您必须像处理普通对象一样处理 Some 字段

    所以设置它为 None 你做的

    movieCollection.updateOne(
                  equal("_id", movie._id),
                  unset("foo")
              )
    

    将其设置为一些

    movieCollection.updateOne(
                  equal("_id", movie._id),
                  set("foo","some_value")
              )
    

    【讨论】:

    • 这仅适用于Option[T],但不适用于A[Option[T]]。解决起来非常令人沮丧,我总是忘记为什么会发生。
    【解决方案2】:

    使用this answer 中的代码,然后将该编解码器添加到您的编解码器注册表中。首先,添加

    import org.bson.codecs.configuration.CodecRegistries.fromCodecs
    

    您可能已经从该包中导入了其他内容;例如,如果您同时使用提供程序、注册表和编解码器:

    import org.bson.codecs.configuration.CodecRegistries.{fromRegistries, fromProviders, fromCodecs}
    

    只需确保您已将所需的所有内容都导入即可。

    然后:

    val codecRegistry = fromRegistries(/* ..., */ fromCodecs(new SomeCodec()), DEFAULT_CODEC_REGISTRY)
    
    val mongoClient = MongoClient("mongodb://127.0.0.1")
    val database = mongoClient.getDatabase("assignment").withCodecRegistry(codecRegistry)
    

    【讨论】:

      【解决方案3】:

      请确保所有字段都转换为Strings。特别是枚举,您希望将字段插入为&lt;your-enum&gt;.map(_.toString)

      【讨论】:

      • 您能否详细解释一下您的答案,尤其是为什么您的提案可能是一个解决方案?
      【解决方案4】:

      导致异常的代码是这样的

      ratingCollection.count(equal("movieId", movie.get("movieId")))
      

      特别是movie.get(...),它的返回类型为Option[BsonValue]。您不能查询具有Option[T] 值的集合。由于您已经检查了 null,您可以将代码更改为 movie.get("movieId").get,但 scala 方法将使用模式匹配,类似于此。

      override def onNext(movie: Document): Unit = {
        movie.get("movieId") match {
          case Some(movieId: BsonValue32) =>
            ratingCollection.count(equal("movieId", movieId)).subscribe(new Observer[Long] {
              override def onError(e: Throwable): Unit = println(s"onError: $e")
              override def onNext(result: Long): Unit = { println(s"In count result : $result") }
              override def onComplete(): Unit = println("onComplete")
            })
          case invalidId => 
            println(s"invalid id ${invalidId}")
        }
      }
      

      根本问题是 mongo scala 驱动程序如何处理 Option[T] monads。它没有很好的记录。 One of the answers already provided to this question 已经展示了如何通过查询 Foo(bar: Option[BsonValue]) 等案例类来解决此问题,但请注意,对于 Foo(bar: Seq[Option[BsonValue]]) 等其他案例类,它会失败。

      正如我参考的答案中提到的,createCodecProviderIgnoreNone 和相关的编解码器提供程序仅适用于完整的文档查询,例如 insertfindReplace 等。在进行现场操作查询时,您必须解压缩 Option你自己。我更喜欢使用模式匹配来做到这一点,例如我的示例中所示。

      【讨论】:

        【解决方案5】:

        这适用于我使用以下版本:

        scalaVersion := "2.13.1"
        sbt.version = 1.3.8
        
        import org.mongodb.scala.bson.ObjectId
        
        object Person {
          def apply(firstName: String, lastName: String): Person =
            Person(new ObjectId(), firstName, lastName)
        }
        case class Person(_id: ObjectId, firstName: String, lastName: String)
        
        import models.Person
        import org.mongodb.scala.{Completed, MongoClient, MongoCollection, MongoDatabase, Observer}
        import org.mongodb.scala.bson.codecs.Macros._
        import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
        import org.bson.codecs.configuration.CodecRegistries.{fromRegistries, fromProviders}
        
        object PersonMain extends App {
        
          val codecRegistry = fromRegistries(fromProviders(classOf[Person]), DEFAULT_CODEC_REGISTRY )
          val mongoClient: MongoClient = MongoClient("mongodb://localhost")
          val database: MongoDatabase = mongoClient.getDatabase("mydb").withCodecRegistry(codecRegistry)
          val collection: MongoCollection[Person] = database.getCollection("people")
        
          def addDocument(doc: Person) = {
            collection.insertOne(doc)
              .subscribe(new Observer[Completed] {
                override def onNext(result: Completed): Unit = println(s"Inserted $doc")
                override def onError(e: Throwable): Unit = println(s"Failed $e")
                override def onComplete(): Unit = println(s"Completed inserting $doc")
              })
          }
        
          addDocument(Person("name", "surname"))
        
          mongoClient.close()
        
        }
        

        【讨论】:

        • 你没有使用任何Option[T] monad
        • @CervEd 您能否重新编写示例以使用它并展示如何正确使用它,而不是仅仅说它不好......不是很有帮助
        • 你的代码中没有Option[T] monad,也没有与使用Option[T] monad 相关的codec exception。请参阅我的答案以获取更多解释stackoverflow.com/a/63282114/1507124
        猜你喜欢
        • 2019-06-19
        • 2017-04-07
        • 2018-11-01
        • 2019-08-31
        • 2017-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多