如何解析对象数组以适配Mongo Scala Driver的Bson文档
嘿,我来帮你搞定这个问题!针对你用Scala + Play Framework + Mongo Scala Driver存储JSON(含对象数组)的需求,我整理了一套清晰的实现步骤:
解决Scala + Play Framework + Mongo Scala Driver存储JSON对象数组的问题
核心思路是先把JSON映射为Scala Case Class,通过Play JSON工具完成序列化/反序列化,再对接Mongo Scala Driver完成存储。
第一步:定义对应JSON的Scala Case Class
首先把你的示例JSON(包括可能的对象数组)转化为强类型的Case Class,这样后续处理更安全。比如假设你的JSON里包含一个contacts对象数组,定义如下:
import java.time.Instant // 嵌套对象:对应数组里的单个元素 case class Contact(name: String, email: String) // 主数据类:完全匹配你的示例JSON结构 case class Enterprise( dateCreationProcess: Instant, sci: Boolean, nomEntreprise: String, siren: String, dateCreation: String, // 如果需要解析为日期类型,可改用LocalDate,后续自定义格式即可 entreeRelation: String, secteur: String, cotationBDF: String, montantPrivileges: String, fcc: String, ca: String, contacts: List[Contact] // 这里对应JSON中的对象数组 )
第二步:生成Play JSON序列化/反序列化规则
Play Framework提供了Json.format宏,可以自动生成Case Class和JSON之间的转换规则,包括数组类型:
import play.api.libs.json._ // 先定义嵌套对象的Format规则 implicit val contactFormat: OFormat[Contact] = Json.format[Contact] // 再定义主类的Format,数组会被自动处理 implicit val enterpriseFormat: OFormat[Enterprise] = Json.format[Enterprise]
如果你的dateCreationProcess是ISO标准时间字符串,需要和Scala的Instant类型互转,可以自定义日期格式:
import play.api.libs.json.Reads._ import play.api.libs.json.Writes._ implicit val instantFormat: Format[Instant] = Format( Reads.instantReads("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), Writes.instantWrites("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") )
第三步:对接Mongo Scala Driver存储数据
这里提供两种常用实现方式,按需选择:
方式1:Play JSON转Mongo Document手动存储
先把Case Class转为Play的JsValue,再转成Mongo的Document对象插入:
import org.mongodb.scala.bson.Document import play.api.libs.json.Json // 创建一个测试用的Enterprise实例 val testEnterprise = Enterprise( dateCreationProcess = Instant.parse("2018-04-18T16:05:21.244Z"), sci = false, nomEntreprise = "a", siren = "a", dateCreation = "20/04/2018", entreeRelation = "08/04/2018", secteur = "AGRICULTEUR PETITE EXPLOITATION", cotationBDF = "a", montantPrivileges = "a", fcc = "a", ca = "a", contacts = List(Contact("John Doe", "john@example.com")) ) // 转为Play JsValue val jsValue = Json.toJson(testEnterprise) // 转为Mongo Document val mongoDoc = Document(Json.stringify(jsValue)) // 插入到Mongo集合 val collection = mongoDatabase.getCollection("enterprises") collection.insertOne(mongoDoc).subscribe( _ => println("数据插入成功!"), e => println(s"插入失败:${e.getMessage}") )
方式2:注册Mongo Codec直接存储Case Class
更优雅的方式是给Mongo注册自定义Codec,让它直接支持Case Class的读写,无需手动转换:
首先确保sbt依赖中包含Mongo的Codec相关库:
libraryDependencies += "org.mongodb.scala" %% "mongo-scala-driver" % "4.11.1" libraryDependencies += "org.mongodb.scala" %% "mongo-scala-bson" % "4.11.1"
然后注册Codec并操作:
import org.mongodb.scala.bson.codecs.Macros import org.bson.codecs.configuration.CodecRegistries.{fromProviders, fromRegistries} import org.mongodb.scala.MongoClient.DEFAULT_CODEC_REGISTRY // 为Case Class创建CodecProvider val contactCodec = Macros.createCodecProvider[Contact]() val enterpriseCodec = Macros.createCodecProvider[Enterprise]() // 合并默认Codec和自定义Codec val codecRegistry = fromRegistries( fromProviders(contactCodec, enterpriseCodec), DEFAULT_CODEC_REGISTRY ) // 获取带自定义Codec的数据库 val mongoDatabase = mongoClient.getDatabase("your_database_name").withCodecRegistry(codecRegistry) // 直接插入Case Class实例 val collection = mongoDatabase.getCollection[Enterprise]("enterprises") collection.insertOne(testEnterprise).subscribe( _ => println("数据插入成功!"), e => println(s"插入失败:${e.getMessage}") )
处理对象数组的关键注意点
- 用Scala的
List[T]或Seq[T]对应JSON中的对象数组 - 只要给数组中的嵌套对象定义好
Format,主类的Json.format宏会自动识别并处理数组 - 如果数组元素是简单类型(如
List[String]),无需额外配置,Play JSON会直接支持
内容的提问来源于stack exchange,提问作者Azoulay Jason
相关产品推荐
相关产品推荐

