使用 scala mongo 驱动程序未将案例 class 的继承元素持久保存到 mongodb
inherited elements of a case class not getting persisted into mongodb using scala mongo driver
我想使用 mongo-scala-driver 2.7.0 坚持使用 mongo 数据库。我的案例class看起来有点像下面
case class App(
@BsonProperty("_id") id: String = "",
appName: String
createdBy: String,
createdAt: Date,
metadata: AppMetadata,
)
sealed class AppMetadata {
final val _t: String = this.getClass.getSimpleName
}
case class App1Metadata(clientId: String,
savedSearches: List[String]
) extends ScopeMetadata
case class App2Metadata(agencyId: String,
randomData: List[Int]
) extends ScopeMetadata
如您所见,应用的元数据可能因应用(App1 和 App2)而大不相同。因此,不可能有一个单一的元数据案例 class 可以被所有应用程序使用。因此,我决定为每个应用程序的元数据设置一个案例 class,如上所示,并从父特征扩展它们。我试图按照 scala mongo 驱动程序的文档 here and another Whosebug question here 来实现这一点。如您所见,我在密封特征中放置了一个 _t
字段。根据文档,这是必需的,因为它将在与 Bson 之间对文档进行解码和编码时用作提示。
这是我的编解码器的样子
def customCodeRegistry() = {
fromProviders(
Macros.createCodecProviderIgnoreNone[App](),
Macros.createCodecProviderIgnoreNone[App1Metadata](),
Macros.createCodecProviderIgnoreNone[App2Metadata]()
)
}
val customCodecRegistry2 = CodecRegistries.fromProviders(Macros.createCodecProvider[ScopeMetadata]())
val codecRegistry = fromRegistries(customCodeRegistry(), DEFAULT_CODEC_REGISTRY,customCodecRegistry2)
我坚持简单地使用
override def addApp(app: App): Future[String] = {
for {
_ <- collection.insertOne(app).toFuture()
} yield user.id
}
保存在 mongo 数据库中的文档缺少 _t field
内部元数据对象,根据文档,这是 Mongo Scala Driver 转换 bson 所必需的到正确的元数据大小写 class,因此当我尝试使用
获取文档时
override def getUser(email: String): Future[Option[User]] = {
collection.find(equal(EMAIL_FIELD, email)).headOption()
}
我在错误消息中收到以下内容
Could not decode sealed case class. Missing '_t' field.
但是,如果我显式地将 _t 字段添加到元数据对象的 mongo 中,其名称为 class,则应该将其解码为,一切正常,我得到正确的大小写 class 在获取操作期间。我不明白为什么虽然使用 mongo insert ,但 _t field
没有被插入
AFAIU 文档,您不需要为每个子类型提供编解码器,_t
应该会自动添加。
docs 说:
you only need create a CodecProvider
for the parent sealed trait/class. Internally an extra field (_t
) is stored alongside the data
所以像这样的东西对你来说应该足够了:
sealed trait AppMetadata
case class App1Metadata(clientId: String, savedSearches: List[String]) extends AppMetadata
case class App2Metadata(agencyId: String, randomData: List[Int]) extends AppMetadata
fromRegistries(fromProviders(classOf[AppMetadata]), DEFAULT_CODEC_REGISTRY)
假设 ScopeMetadata
与 AppMetadata
相同。
我想使用 mongo-scala-driver 2.7.0 坚持使用 mongo 数据库。我的案例class看起来有点像下面
case class App(
@BsonProperty("_id") id: String = "",
appName: String
createdBy: String,
createdAt: Date,
metadata: AppMetadata,
)
sealed class AppMetadata {
final val _t: String = this.getClass.getSimpleName
}
case class App1Metadata(clientId: String,
savedSearches: List[String]
) extends ScopeMetadata
case class App2Metadata(agencyId: String,
randomData: List[Int]
) extends ScopeMetadata
如您所见,应用的元数据可能因应用(App1 和 App2)而大不相同。因此,不可能有一个单一的元数据案例 class 可以被所有应用程序使用。因此,我决定为每个应用程序的元数据设置一个案例 class,如上所示,并从父特征扩展它们。我试图按照 scala mongo 驱动程序的文档 here and another Whosebug question here 来实现这一点。如您所见,我在密封特征中放置了一个 _t
字段。根据文档,这是必需的,因为它将在与 Bson 之间对文档进行解码和编码时用作提示。
这是我的编解码器的样子
def customCodeRegistry() = {
fromProviders(
Macros.createCodecProviderIgnoreNone[App](),
Macros.createCodecProviderIgnoreNone[App1Metadata](),
Macros.createCodecProviderIgnoreNone[App2Metadata]()
)
}
val customCodecRegistry2 = CodecRegistries.fromProviders(Macros.createCodecProvider[ScopeMetadata]())
val codecRegistry = fromRegistries(customCodeRegistry(), DEFAULT_CODEC_REGISTRY,customCodecRegistry2)
我坚持简单地使用
override def addApp(app: App): Future[String] = {
for {
_ <- collection.insertOne(app).toFuture()
} yield user.id
}
保存在 mongo 数据库中的文档缺少 _t field
内部元数据对象,根据文档,这是 Mongo Scala Driver 转换 bson 所必需的到正确的元数据大小写 class,因此当我尝试使用
override def getUser(email: String): Future[Option[User]] = {
collection.find(equal(EMAIL_FIELD, email)).headOption()
}
我在错误消息中收到以下内容
Could not decode sealed case class. Missing '_t' field.
但是,如果我显式地将 _t 字段添加到元数据对象的 mongo 中,其名称为 class,则应该将其解码为,一切正常,我得到正确的大小写 class 在获取操作期间。我不明白为什么虽然使用 mongo insert ,但 _t field
没有被插入
AFAIU 文档,您不需要为每个子类型提供编解码器,_t
应该会自动添加。
docs 说:
you only need create a
CodecProvider
for the parent sealed trait/class. Internally an extra field (_t
) is stored alongside the data
所以像这样的东西对你来说应该足够了:
sealed trait AppMetadata
case class App1Metadata(clientId: String, savedSearches: List[String]) extends AppMetadata
case class App2Metadata(agencyId: String, randomData: List[Int]) extends AppMetadata
fromRegistries(fromProviders(classOf[AppMetadata]), DEFAULT_CODEC_REGISTRY)
假设 ScopeMetadata
与 AppMetadata
相同。