メインコンテンツへスキップ

複合型

警告

複合型はMongoDBでのみ利用可能です。

複合型(MongoDBでは組み込みドキュメントとして知られる)を使用すると、レコード内に他のレコードを埋め込むことができます。

複合型はv3.12.0で一般公開されました。以前はv3.10.0からプレビュー版として利用可能でした。

このページでは、以下の方法を説明します。

  • findFirstfindManyを使用して複合型を含むレコードを検索する
  • createcreateManyを使用して複合型を持つ新しいレコードを作成する
  • updateupdateManyを使用して既存のレコード内の複合型を更新する
  • deletedeleteManyを使用して複合型を持つレコードを削除する

スキーマ例

以下の例ではこのスキーマを使用します

schema.prisma
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}

model Product {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String @unique
price Float
colors Color[]
sizes Size[]
photos Photo[]
orders Order[]
}

model Order {
id String @id @default(auto()) @map("_id") @db.ObjectId
product Product @relation(fields: [productId], references: [id])
color Color
size Size
shippingAddress Address
billingAddress Address?
productId String @db.ObjectId
}

enum Color {
Red
Green
Blue
}

enum Size {
Small
Medium
Large
XLarge
}

type Photo {
height Int @default(200)
width Int @default(100)
url String
}

type Address {
street String
city String
zip String
}

このスキーマでは、ProductモデルにPhoto[]複合型があり、Orderモデルには2つの複合Address型があります。shippingAddressは必須ですが、billingAddressはオプションです。

複合型を使用する際の考慮事項

現在、Prisma Clientで複合型を使用する際にはいくつかの制限があります。

複合型の必須フィールドのデフォルト値

バージョン4.0.0以降、以下のすべての条件が満たされている場合に複合型に対してデータベース読み取りを実行すると、Prisma Clientは結果にデフォルト値を挿入します。

条件

  • 複合型のフィールドが必須であり、かつ
  • このフィールドにデフォルト値があり、かつ
  • このフィールドが返されたドキュメントに存在しない場合。

  • これはモデルフィールドと同じ動作です。
  • 読み取り操作では、Prisma Clientはデフォルト値を結果に挿入しますが、データベースには挿入しません。

例のスキーマで、photoに必須フィールドを追加するとします。このフィールド、bitDepthにはデフォルト値があります。

schema.prisma
...
type Photo {
...
bitDepth Int @default(8)
}

...

その後、npx prisma db pushを実行してデータベースを更新し、npx prisma generateでPrisma Clientを再生成するとします。次に、以下のアプリケーションコードを実行します。

console.dir(await prisma.product.findMany({}), { depth: Infinity })

bitDepthフィールドは追加されたばかりのため内容がないため、クエリはデフォルト値の8を返します。

** 以前のバージョン **

バージョン4.0.0以前では、Prisma ORMはP2032エラーを次のようにスローしました。

Error converting field "bitDepth" of expected non-nullable
type "int", found incompatible value of "null".

findおよびfindManyで複合型を含むレコードを検索する

レコードはwhere操作内で複合型によってフィルタリングできます。

次のセクションでは、単一型または複数型でフィルタリングするための利用可能な操作について説明し、それぞれの例を示します。

単一の複合型でフィルタリングする

isequalsisNot、およびisSet操作を使用して単一の複合型を変更します。

  • is: 複合型が一致する結果をフィルタリングします。1つ以上のフィールドが存在する必要があります。(例:配送先住所のストリート名で注文をフィルタリングする)
  • equals: 複合型が一致する結果をフィルタリングします。すべてのフィールドが存在する必要があります。(例:完全な配送先住所で注文をフィルタリングする)
  • isNot: 複合型が一致しない結果をフィルタリングします。
  • isSet : オプションフィールドをフィルタリングして、設定されている結果(値に設定されているか、明示的にnullに設定されているか)のみを含めます。このフィルターをtrueに設定すると、まったく設定されていないundefinedの結果が除外されます。

例えば、isを使用して、ストリート名が'555 Candy Cane Lane'の注文をフィルタリングします。

const orders = await prisma.order.findMany({
where: {
shippingAddress: {
is: {
street: '555 Candy Cane Lane',
},
},
},
})

equalsを使用して、配送先住所のすべてのフィールドが一致する注文をフィルタリングします。

const orders = await prisma.order.findMany({
where: {
shippingAddress: {
equals: {
street: '555 Candy Cane Lane',
city: 'Wonderland',
zip: '52337',
},
},
},
})

このクエリでは、equalsを省略した短縮表記も使用できます。

const orders = await prisma.order.findMany({
where: {
shippingAddress: {
street: '555 Candy Cane Lane',
city: 'Wonderland',
zip: '52337',
},
},
})

isNotを使用して、郵便番号が'52337'でない注文をフィルタリングします。

const orders = await prisma.order.findMany({
where: {
shippingAddress: {
isNot: {
zip: '52337',
},
},
},
})

isSetを使用して、オプションのbillingAddressが設定されている(値に設定されているか、nullに設定されているか)注文をフィルタリングします。

const orders = await prisma.order.findMany({
where: {
billingAddress: {
isSet: true,
},
},
})

複数の複合型でフィルタリングする

equalsisEmptyeverysome、およびnone操作を使用して、複数の複合型をフィルタリングします。

  • equals: リストの完全な一致を確認します。
  • isEmpty: リストが空かどうかを確認します。
  • every: リスト内のすべての項目が条件に一致する必要があります。
  • some: リスト内の1つ以上の項目が条件に一致する必要があります。
  • none: リスト内のどの項目も条件に一致してはなりません。
  • isSet : オプションフィールドをフィルタリングして、設定されている結果(値に設定されているか、明示的にnullに設定されているか)のみを含めます。このフィルターをtrueに設定すると、まったく設定されていないundefinedの結果が除外されます。

例えば、equalsを使用して、特定の写真リストを持つ製品を見つけることができます(urlheightwidthのすべてのフィールドが一致する必要があります)。

const product = prisma.product.findMany({
where: {
photos: {
equals: [
{
url: '1.jpg',
height: 200,
width: 100,
},
{
url: '2.jpg',
height: 200,
width: 100,
},
],
},
},
})

このクエリでは、equalsを省略し、フィルタリングしたいフィールドのみを指定する短縮表記も使用できます。

const product = prisma.product.findMany({
where: {
photos: [
{
url: '1.jpg',
height: 200,
width: 100,
},
{
url: '2.jpg',
height: 200,
width: 100,
},
],
},
})

isEmptyを使用して、写真がない製品をフィルタリングします。

const product = prisma.product.findMany({
where: {
photos: {
isEmpty: true,
},
},
})

someを使用して、1つ以上の写真のurl"2.jpg"である製品をフィルタリングします。

const product = prisma.product.findFirst({
where: {
photos: {
some: {
url: '2.jpg',
},
},
},
})

noneを使用して、写真のurl"2.jpg"でない製品をフィルタリングします。

const product = prisma.product.findFirst({
where: {
photos: {
none: {
url: '2.jpg',
},
},
},
})

createおよびcreateManyで複合型を持つレコードを作成する

情報

複合型を伴うレコードを作成する際に一意性制約がある場合、MongoDBはレコード内部の一意な値を強制しないことに注意してください。詳細はこちら

複合型は、createまたはcreateManyメソッド内でset操作を使用して作成できます。例えば、create内でsetを使用して、Order内にAddress複合型を作成できます。

const order = await prisma.order.create({
data: {
// Normal relation
product: { connect: { id: 'some-object-id' } },
color: 'Red',
size: 'Large',
// Composite type
shippingAddress: {
set: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
},
},
})

setを省略し、作成したいフィールドのみを指定する短縮表記も使用できます。

const order = await prisma.order.create({
data: {
// Normal relation
product: { connect: { id: 'some-object-id' } },
color: 'Red',
size: 'Large',
// Composite type
shippingAddress: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
},
})

billingAddressのようなオプション型の場合、値をnullに設定することもできます。

const order = await prisma.order.create({
data: {
// Normal relation
product: { connect: { id: 'some-object-id' } },
color: 'Red',
size: 'Large',
// Composite type
shippingAddress: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
// Embedded optional type, set to null
billingAddress: {
set: null,
},
},
})

製品が複数の写真のリストを含むケースをモデル化するには、複数の複合型を一度に設定できます。

const product = await prisma.product.create({
data: {
name: 'Forest Runners',
price: 59.99,
colors: ['Red', 'Green'],
sizes: ['Small', 'Medium', 'Large'],
// New composite type
photos: {
set: [
{ height: 100, width: 200, url: '1.jpg' },
{ height: 100, width: 200, url: '2.jpg' },
],
},
},
})

setを省略し、作成したいフィールドのみを指定する短縮表記も使用できます。

const product = await prisma.product.create({
data: {
name: 'Forest Runners',
price: 59.99,
// Scalar lists that we already support
colors: ['Red', 'Green'],
sizes: ['Small', 'Medium', 'Large'],
// New composite type
photos: [
{ height: 100, width: 200, url: '1.jpg' },
{ height: 100, width: 200, url: '2.jpg' },
],
},
})

これらの操作はcreateManyメソッド内でも機能します。例えば、それぞれ写真のリストを含む複数の製品を作成できます。

const product = await prisma.product.createMany({
data: [
{
name: 'Forest Runners',
price: 59.99,
colors: ['Red', 'Green'],
sizes: ['Small', 'Medium', 'Large'],
photos: [
{ height: 100, width: 200, url: '1.jpg' },
{ height: 100, width: 200, url: '2.jpg' },
],
},
{
name: 'Alpine Blazers',
price: 85.99,
colors: ['Blue', 'Red'],
sizes: ['Large', 'XLarge'],
photos: [
{ height: 100, width: 200, url: '1.jpg' },
{ height: 150, width: 200, url: '4.jpg' },
{ height: 200, width: 200, url: '5.jpg' },
],
},
],
})

updateおよびupdateManyで複合型を変更する

情報

複合型を伴うレコードを更新する際に一意性制約がある場合、MongoDBはレコード内部の一意な値を強制しないことに注意してください。詳細はこちら

複合型は、updateまたはupdateManyメソッド内で設定、更新、または削除できます。次のセクションでは、単一型または複数型を一度に更新するための利用可能な操作について説明し、それぞれの例を示します。

単一の複合型を変更する

setunsetupdate、およびupsert操作を使用して単一の複合型を変更します。

  • setを使用して複合型を設定し、既存の値を上書きします。
  • unsetを使用して複合型を解除します。set: nullとは異なり、unsetはフィールドを完全に削除します。
  • updateを使用して複合型を更新します。
  • upsertを使用して、複合型が存在する場合は既存の複合型をupdateし、そうでない場合は複合型をsetします。

例えば、updateを使用して、Order内の必須のshippingAddressAddress複合型で更新します。

const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
shippingAddress: {
// Update just the zip field
update: {
zip: '41232',
},
},
},
})

billingAddressのようなオプションの埋め込み型の場合、upsertを使用して、存在しない場合は新しいレコードを作成し、存在する場合はレコードを更新します。

const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
billingAddress: {
// Create the address if it doesn't exist,
// otherwise update it
upsert: {
set: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
update: {
zip: '84323',
},
},
},
},
})

unset操作を使用してオプションの埋め込み型を削除することもできます。次の例では、unsetを使用してOrderからbillingAddressを削除しています。

const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
billingAddress: {
// Unset the billing address
// Removes "billingAddress" field from order
unset: true,
},
},
})

updateMany内でフィルターを使用して、複合型に一致するすべてのレコードを更新できます。次の例では、isフィルターを使用して、注文リストの配送先住所のストリート名に一致させています。

const orders = await prisma.order.updateMany({
where: {
shippingAddress: {
is: {
street: '555 Candy Cane Lane',
},
},
},
data: {
shippingAddress: {
update: {
street: '111 Candy Cane Drive',
},
},
},
})

複数の複合型を変更する

setpushupdateMany、およびdeleteMany操作を使用して、複合型のリストを変更します。

  • set: 複合型の埋め込みリストを設定し、既存のリストを上書きします。
  • push: 複合型の埋め込みリストの最後に値をプッシュします。
  • updateMany: 複数の複合型を一度に更新します。
  • deleteMany: 複数の複合型を一度に削除します。

例えば、pushを使用してphotosリストに新しい写真を追加します。

const product = prisma.product.update({
where: {
id: '62de6d328a65d8fffdae2c18',
},
data: {
photos: {
// Push a photo to the end of the photos list
push: [{ height: 100, width: 200, url: '1.jpg' }],
},
},
})

updateManyを使用して、url1.jpgまたは2.pngの写真 を更新します。

const product = prisma.product.update({
where: {
id: '62de6d328a65d8fffdae2c18',
},
data: {
photos: {
updateMany: {
where: {
url: '1.jpg',
},
data: {
url: '2.png',
},
},
},
},
})

次の例では、deleteManyを使用して、高さが100の写真 をすべて削除しています。

const product = prisma.product.update({
where: {
id: '62de6d328a65d8fffdae2c18',
},
data: {
photos: {
deleteMany: {
where: {
height: 100,
},
},
},
},
})

upsertで複合型をアップサートする

情報

一意性制約を持つ複合型内の値を作成または更新する場合、MongoDBはレコード内部の一意な値を強制しないことに注意してください。詳細はこちら

複合型を作成または更新するには、upsertメソッドを使用します。上記のcreateおよびupdateメソッドと同じ複合操作を使用できます。

例えば、upsertを使用して、新しい製品を作成するか、既存の製品に写真を追加します。

const product = await prisma.product.upsert({
where: {
name: 'Forest Runners',
},
create: {
name: 'Forest Runners',
price: 59.99,
colors: ['Red', 'Green'],
sizes: ['Small', 'Medium', 'Large'],
photos: [
{ height: 100, width: 200, url: '1.jpg' },
{ height: 100, width: 200, url: '2.jpg' },
],
},
update: {
photos: {
push: { height: 300, width: 400, url: '3.jpg' },
},
},
})

deleteおよびdeleteManyで複合型を含むレコードを削除する

複合型を埋め込むレコードを削除するには、deleteまたはdeleteManyメソッドを使用します。これにより、埋め込み複合型も削除されます。

例えば、deleteManyを使用して、サイズが"Small"のすべての製品を削除します。これにより、埋め込みphotosも削除されます。

const deleteProduct = await prisma.product.deleteMany({
where: {
sizes: {
equals: 'Small',
},
},
})

フィルターを使用して、複合型に一致するレコードを削除することもできます。以下の例では、someフィルターを使用して、特定の写真を含む製品を削除しています。

const product = await prisma.product.deleteMany({
where: {
photos: {
some: {
url: '2.jpg',
},
},
},
})

複合型の順序付け

orderBy操作を使用して、結果を昇順または降順でソートできます。

例えば、次のコマンドはすべての注文を検索し、配送先住所の都市名で昇順に並べ替えます。

const orders = await prisma.order.findMany({
orderBy: {
shippingAddress: {
city: 'asc',
},
},
})

複合型の一意フィールドにおける重複値

一意性制約を持つ複合型を持つレコードに対して以下のいずれかの操作を実行する際には注意が必要です。この状況では、MongoDBはレコード内部の一意な値を強制しません。

  • レコードを作成するとき
  • レコードにデータを追加するとき
  • レコードのデータを更新するとき

スキーマに@@unique制約を持つ複合型がある場合、MongoDBは、この複合型を含む2つ以上のレコードで、制約付きの値に同じ値を保存することを防ぎます。ただし、MongoDBは1つのレコード内に同じフィールド値を複数コピー保存することを妨げません。

この問題をPrisma ORMリレーションを使用して回避できることに注意してください。

例えば、以下のスキーマでは、MailBoxは複合型addressesを持ち、emailフィールドに@@unique制約があります。

type Address {
email String
}

model MailBox {
name String
addresses Address[]

@@unique([addresses.email])
}

以下のコードは、addressに2つの同一の値を持つレコードを作成します。MongoDBはこの状況でエラーをスローせず、alice@prisma.ioaddressesに2回保存します。

await prisma.MailBox.createMany({
data: [
{
name: 'Alice',
addresses: {
set: [
{
address: 'alice@prisma.io', // Not unique
},
{
address: 'alice@prisma.io', // Not unique
},
],
},
},
],
})

注:異なる2つのレコードに同じ値を保存しようとすると、MongoDBはエラーをスローします。上記の例では、ユーザーAliceとユーザーBobに対してメールアドレスalice@prisma.ioを保存しようとすると、MongoDBはデータを保存せずエラーをスローします。

Prisma ORMリレーションを使用してレコード内の一意な値を強制する

上記の例では、MongoDBはネストされたアドレス名の一意性制約を強制しませんでした。ただし、レコード内の一意な値を強制するためにデータを異なる方法でモデル化できます。そのためには、Prisma ORMのリレーションを使用して複合型をコレクションに変換します。このコレクションに関係を設定し、一意にしたいフィールドに一意性制約を配置します。

次の例では、MongoDBはレコード内の一意な値を強制します。MailboxAddressモデルの間にはリレーションがあります。また、Addressモデルのnameフィールドには一意性制約があります。

model Address {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
mailbox Mailbox? @relation(fields: [mailboxId], references: [id])
mailboxId String? @db.ObjectId

@@unique([name])
}

model Mailbox {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
addresses Address[] @relation
}
await prisma.MailBox.create({
data: {
name: 'Alice',
addresses: {
create: [
{ name: 'alice@prisma.io' }, // Not unique
{ name: 'alice@prisma.io' }, // Not unique
],
},
},
})

上記のコードを実行すると、MongoDBは一意性制約を強制します。アプリケーションがalice@prisma.ioという名前の2つのアドレスを追加することは許可されません。

© 2025 prisma.dokyumento.jp. All rights reserved.