我定义了BSONDocumentWriters以使用reactivemongo驱动程序将域对象(case类)映射到要在mongodb中持久化的bson文档。对于case类来说,定义writer是非常直接的(尽管冗长且容易出错:我希望有一个类似salat的解决方案)。但是,对于Map[String,Any](其中的值可以是numeric、date或string类型)我似乎无法执行相同的操作。我发现了一个code example定义了一个映射的通用writer(和reader):

implicit def MapWriter[V](implicit vw: BSONDocumentWriter[V]): BSONDocumentWriter[Map[String, V]] =
  new BSONDocumentWriter[Map[String, V]] {
  def write(map: Map[String, V]): BSONDocument = {
    val elements = map.toStream.map { tuple =>
      tuple._1 -> vw.write(tuple._2)
    }
    BSONDocument(elements)
  }
}

但如果类型BSONDocumentWriter没有隐式V,即代码片段:
BSONDocument(
  "_id" -> "asd",
  "map" -> MapWriter[Any].write(Map("x" -> 1, "y" -> "2"))
)

不编译:
could not find implicit value for parameter vw: reactivemongo.bson.BSONDocumentWriter[Any]
    "map" -> MapWriter[Any].write(Map("x" -> 1, "y" -> "2"))
                      ^

我想也许作者应该写信给aBSONValue而不是aBSONDocument,所以我修改了示例如下:
implicit def ValueMapWriter[V](implicit vw: BSONWriter[V, BSONValue]): BSONDocumentWriter[Map[String, V]] =
  new BSONDocumentWriter[Map[String, V]] {
  def write(map: Map[String, V]): BSONDocument = {
    val elements = map.toStream.map {
      tuple =>
        tuple._1 -> vw.write(tuple._2)
    }
    BSONDocument(elements)
  }
}

为了简单起见,我尝试使用Int作为值类型,但同样,代码片段:
BSONDocument(
  "_id" -> "asd",
  "map" -> ValueMapWriter[Int].write(Map("x" -> 1, "y" -> 2))
)

不编译:
could not find implicit value for parameter vw: reactivemongo.bson.BSONWriter[Int,reactivemongo.bson.BSONValue]
    "map" -> ValueMapWriter[Int].write(Map("x" -> 1, "y" -> 2))
                          ^

如果上面的方法有效的话,我可以使用一些基类作为值类型并定义它的隐式writer。
我不知道为什么会发生这种事,也不知道我怎么能解决。也许我遗漏了一些显而易见的东西?思想?

最佳答案

ValueMapWriter定义中bsonValue的泛型类型参数边界不正确。如果你换线

implicit def ValueMapWriter[V](implicit vw: BSONWriter[V, BSONValue]): BSONDocumentWriter[Map[String, V]] =

具有
implicit def ValueMapWriter[V](implicit vw: BSONWriter[V, _ <: BSONValue]): BSONDocumentWriter[Map[String, V]] =

然后它应该解析int的隐式writer。
顺便说一下,simple-reactivemongo已经这样做了。我还计划将此功能添加到ReactiveMongo Extensions

07-28 09:37