You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解析对象数组以适配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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:00:43