AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。
Docs Menu

タイプ コーデックによるデータのエンコード

このガイドでは、ScalaドライバーでScalaオブジェクトとBSONデータのエンコードとデコードを処理するコーデックとサポート クラスについて学習できます。The Codec Scala abstraction allows you to map any Scala type to a corresponding BSON type.これを使用して、DocumentBsonDocument などの中間マップベースのオブジェクトに依存する代わりに、ドメイン オブジェクトをBSONとの間で直接マップします。

Codec インターフェースには、Scala オブジェクトを BSON データとの間でエンコードおよびデコードするための抽象メソッドが含まれています。これらのメソッドを実装して、BSON と、ユーザーの Codec 実装の Scala 型の間の変換ロジックを定義します。

Codecencode()インターフェースを実装するには、インターフェースの 、decode()getEncoderClass() メソッドを定義します。これらのメソッドを実装するコード例については、「 基本的なカスタム コーデックの例 」セクションを参照してください。

encode() メソッドは Scala 型のインスタンスを BSON にエンコードします。これにより、ドライバーはインスタンスを MongoDB に保存できます。このメソッドには次のパラメータが必要です。

Parameter Type
説明

writer

BSON ドキュメントを書き込むためのメソッドを公開するインターフェースである BsonWriter を実装するクラスのインスタンス。このインスタンスを使用して、BSON 値の型に合わせて適切な書き込みメソッドを使用して BSON 値を書き込みます。

value

メソッドがエンコードするデータ。value 型は、Codec 実装に割り当てた型パラメータと一致する必要があります。

encoderContext

現在の値を MongoDB コレクションに保存するかどうかなど、メソッドが BSON にエンコードする Scala オブジェクトに関するメタデータ。

encode() メソッドは値を返しません。

decode() メソッドは、BSON データを使用して Scala 型のインスタンスをデコードします。このメソッドには次のパラメータが必要です。

Parameter Type
説明

bsonReader

BSON ドキュメントを読み取るためのメソッドを公開するインターフェースである BsonReader を実装するクラスのインスタンス。

decoderContext

メソッドが Scala オブジェクトにデコードする BSON データに関するメタデータ。

getEncoderClass() メソッドは、Codec で定義された Scala 型のインスタンスを返します。このメソッドは、Java 虚擬マシン (JVM) がランタイムに消去する型情報を提供します。

次のコード サンプルでは、PowerStatus シールドトレイトと PowerStatusCodec クラスを使用して、カスタム Codec を実装する方法を示します。

PowerStatus シールドトレイトは、電気スイッチの状態を表すのにケースオブジェクト OnOff を使用します。

sealed trait PowerStatus
object PowerStatus {
case object On extends PowerStatus
case object Off extends PowerStatus
}

PowerStatusCodec クラスは Codec を実装して、PowerStatus 値を対応する BSON ブール値にエンコードします。encode() メソッドは PowerStatus 値を BSON ブール値にエンコードし、decode() メソッドは BSON ブール値を PowerStatus 値にデコードします。

class PowerStatusCodec extends Codec[PowerStatus] {
override def encode(writer: BsonWriter, value: PowerStatus,
encoderContext: EncoderContext): Unit = {
if (value != null) {
writer.writeBoolean(value == PowerStatus.On)
}
}
override def decode(reader: BsonReader,
decoderContext: DecoderContext): PowerStatus = {
if (reader.readBoolean()) PowerStatus.On else PowerStatus.Off
}
override def getEncoderClass: Class[PowerStatus] = classOf[PowerStatus]
}

PowerStatusCodecクラスを使用するには、クラスのインスタンスをCodecRegistry Codecインターフェースに追加する必要があります。これにより、 は対応するScala型にマッピングされます。ドライバーは、CodecRegistry Codecにそのタイプの が含まれている場合にのみ、タイプをエンコードおよびデコードできます。カスタム をCodec CodecRegistryインターフェースに含める方法については、このページの「CodecRegistry」セクションを参照してください。

このセクションのクラスとインターフェースの詳細については、次の API ドキュメントを参照してください。

CodecRegistry は、Codec インスタンスの不可変コレクションです。CodecRegistry インスタンスを構築するには、次の CodecRegistries クラスの静的ファクトリメソッドのいずれかを使用します。各メソッドは、異なる Codec インスタンスのソースからレジストリをビルドします。

方式
説明

fromCodecs()

メソッドに渡すCodecインスタンスからレジストリをビルドする

fromProviders()

メソッドに渡す CodecProvider インスタンスが提供する Codec インスタンスからレジストリを構築します

fromRegistries()

メソッドに渡す他の CodecRegistry インスタンスを結合してレジストリをビルドします。

次の例では、2 つの Codec 実装を使用しています。

  • IntegerCodec: BSON パッケージ内の Codec で、Java Integer 値を BSON 32ビット整数値にエンコードします。

  • PowerStatusCodec: CodecPowerStatus値をBSONブール値にデコードするサンプル 。

次の例は、fromCodecs() メソッドを使用してこれらの実装をレジストリに割り当てることで CodecRegistry インスタンスを構築する方法を示しています。

val codecRegistry = CodecRegistries.fromCodecs(
new IntegerCodec(), new PowerStatusCodec()
)

次の例では、前の例の Codec インスタンスを CodecRegistry コレクションから取得します。

val powerStatusCodec: Codec[PowerStatus] =
codecRegistry.get(classOf[PowerStatus])
val integerCodec: Codec[Integer] =
codecRegistry.get(classOf[Integer])

注意

未登録のクラスのCodecインスタンスでget()メソッドを呼び出すと、ドライバーはCodecConfigurationExceptionをスローします。

デフォルトのコーデックCodecProvider レジストリは、一般的に使用されるScalaとMongoDB型間でエンコードする クラスのセットです。カスタム コーデック レジストリを指定しない限り、ドライバーは自動的にデフォルトのコーデック レジストリを使用します。CodecProvider インターフェースの詳細については、 CodecProvider セクションを参照してください。

1 つ以上の Codec クラスの動作をオーバーライドする必要があり、他のクラスのデフォルトのコーデック レジストリの動作を維持する場合は、優先順位に従ってすべてのレジストリを指定できます。たとえば、カスタム型の Codec のデフォルトのプロバイダー動作をカスタム MyEnumCodec でオーバーライドするには、デフォルトのコーデック レジストリの前にレジストリ リストに追加します。次の例はこのパターンを示しています。

val newRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new MyEnumCodec()),
MongoClientSettings.getDefaultCodecRegistry()
)

このセクションのクラスとインターフェースの詳細については、次の API ドキュメントを参照してください。

CodecProvider インターフェースには、Codec インスタンスを作成し、それを CodecRegistry インスタンスに割り当てる抽象メソッドが含まれています。CodecRegistry インターフェースと同様に、CodecProvider インターフェースは Codec インスタンスを返す get() メソッドを定義します。BSON ライブラリはこれらの Codec インスタンスを使用して、Scala と BSON データ型間でエンコードします。

コードにクラスを追加する場合は、そのフィールドに対応する Codec オブジェクトが必要な場合は CodecProvider を使用します。各フィールドに固有の Codec インスタンスが必要な場合は、クラスの Codec インスタンスをインスタンス化する前に、各フィールドの Codec オブジェクトをインスタンス化する必要があります。get() メソッドの CodecRegistry パラメータを使用して、Codec が依存する Codec インスタンスのいずれかをコンストラクタに渡します。

次の例は、CodecProvider インターフェースを実装する方法を示しています。ドライバーは、実装された MonolightCodecProvider インターフェースを使用して、 Monolight クラスの MonolightCodec インスタンスを作成します。

class MonolightCodecProvider extends CodecProvider {
override def get[T](clazz: Class[T], registry: CodecRegistry): Codec[T] = {
if (clazz == classOf[Monolight]) {
new MonolightCodec(registry).asInstanceOf[Codec[T]]
} else {
null
}
}
}

CodecProviderカスタム クラスを含む インターフェースの完全な実装については、このガイドの「 完全なカスタム コーデックの例 」セクションを参照してください。

このセクションのクラスとインターフェースの詳細については、次の API ドキュメントを参照してください。

このセクションでは、Codec および CodecProvider インターフェースを実装してカスタム Scala クラスのエンコードおよびデコード ロジックを定義する方法を学べることができます。このセクションでは、カスタム実装を指定して使用し、挿入操作と検索操作を実行する方法も示します。

次のコード スニペットは、例としてのカスタム クラス Monolight とそのフィールドを示しています。

case class Monolight(
powerStatus: PowerStatus = PowerStatus.Off,
colorTemperature: Int = 0
)

Monolight クラスには次のフィールドが含まれており、それぞれに Codec インターフェースの**実装**が必要です。

  • powerStatus ライトがオンまたはオフに切り替えられたかどうかを示します。 PowerStatusCodecクラスは PowerStatus値をBSONブール値にエンコードします。

  • colorTemperature はライトの色を記述し、Int 値が含まれます。BSON ライブラリに含まれる IntegerCodec クラスは、colorTemperature 値を BSON 32ビット整数にエンコードします。

次のコード例は、Monolight クラスに Codec インターフェースを実装する方法を示しています。コンストラクターは CodecRegistry インスタンスを使用して、Monolight フィールドをエンコードおよびデコードするために必要な Codec インスタンスを検索します。

class MonolightCodec(registry: CodecRegistry) extends Codec[Monolight] {
private val powerStatusCodec: Codec[PowerStatus] =
registry.get(classOf[PowerStatus])
private val integerCodec: Codec[Integer] =
registry.get(classOf[Integer])
override def encode(writer: BsonWriter, value: Monolight,
encoderContext: EncoderContext): Unit = {
writer.writeStartDocument()
writer.writeName("powerStatus")
powerStatusCodec.encode(writer, value.powerStatus, encoderContext)
writer.writeName("colorTemperature")
integerCodec.encode(writer, value.colorTemperature, encoderContext)
writer.writeEndDocument()
}
override def decode(reader: BsonReader,
decoderContext: DecoderContext): Monolight = {
var powerStatus: PowerStatus = PowerStatus.Off
var colorTemperature: Int = 0
reader.readStartDocument()
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
reader.readName() match {
case "powerStatus" =>
powerStatus = powerStatusCodec.decode(reader, decoderContext)
case "colorTemperature" =>
colorTemperature = integerCodec.decode(reader, decoderContext)
case "_id" =>
reader.readObjectId()
case _ =>
reader.skipValue()
}
}
reader.readEndDocument()
Monolight(powerStatus, colorTemperature)
}
override def getEncoderClass: Class[Monolight] = classOf[Monolight]
}

以下のコード例は、Monolight クラスのフィールドの Codec インスタンスを構築し、カスタム CodecProvider を実装する方法を示しています。

class MonolightCodecProvider extends CodecProvider {
override def get[T](clazz: Class[T], registry: CodecRegistry): Codec[T] = {
if (clazz == classOf[Monolight]) {
new MonolightCodec(registry).asInstanceOf[Codec[T]]
} else {
null
}
}
}

get() メソッドは、ドライバーが Monolight クラスの Codec をリクエストすると、新しい MonolightCodec を返します。メソッドは CodecRegistryMonolightCodec コンストラクタに渡し、MonolightCodecPowerStatusCodecIntegerCodec などのフィールドの Codec インスタンスを取得できるようにします。ドライバーが他のクラスの Codec をリクエストすると、メソッドは null を返します。

変換ロジックを定義した後、次の操作を実行できます。

  • Monolight クラスのインスタンスのデータを MongoDB に保存する

  • MongoDBから Monolightクラスのインスタンスにデータを取得する

次の例では、MonolightCodecProvider クラスを withCodecRegistry() メソッドに渡すことで、MongoCollection インスタンスに割り当てています。次に、insertOne() メソッドを呼び出して新しい Monolight インスタンスをコレクションに挿入し、find() メソッドを呼び出して保存された Monolight インスタンスを返します。出力には、取得された Monolight インスタンスが表示され、カスタム コーデックがデータを正常にエンコードおよびデコードしたことが確認されます。

object MonolightCodecExample {
def main(args: Array[String]): Unit = {
val uri = "<connection string URI>"
val mongoClient = MongoClient(uri)
val codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(
new IntegerCodec(), new PowerStatusCodec()
),
CodecRegistries.fromProviders(new MonolightCodecProvider()),
MongoClientSettings.getDefaultCodecRegistry()
)
val database = mongoClient.getDatabase("codecs_example_products")
val collection: MongoCollection[Monolight] = database
.getCollection[Monolight]("monolights")
.withCodecRegistry(codecRegistry)
val myMonolight = Monolight(PowerStatus.On, 5200)
Await.result(
collection.insertOne(myMonolight).toFuture(),
Duration.Inf
)
val lights = Await.result(
collection.find().toFuture(),
Duration.Inf
)
println(lights)
mongoClient.close()
}
}

このセクションで説明されるメソッドとクラスの詳細については、次の API ドキュメントを参照してください。