Prisma关联MongoDB时可选唯一字段为空触发唯一约束错误
解决Prisma中可选唯一字段触发约束错误的问题
问题根源
你遇到的问题是MongoDB的特性导致的:MongoDB的唯一索引会将null视为一个具体的有效值,因此当你创建多个未设置pixPaymentId(值为null)的Order文档时,这些重复的null值会触发唯一约束错误。第一次创建成功是因为此时索引中只有一个null,第二次插入时就出现了重复。
解决方案
方案1:移除不必要的@unique约束
如果你的业务逻辑只需要Order和Payment之间的一对一关联,不需要pixPaymentId、creditCardPaymentId、boletoPaymentId全局唯一,直接去掉这些字段的@unique注解即可:
model Order { id String @id @default(auto()) @map("_id") @db.ObjectId customer User @relation(fields: [customerId], references: [id]) customerId String @db.ObjectId products Json status String @default("pending") paymentMethod String? pixPayment Payment? @relation(name: "pixPayment", fields: [pixPaymentId], references: [id]) pixPaymentId String? @db.ObjectId // 移除@unique creditCardPayment Payment? @relation(name: "creditCardPayment", fields: [creditCardPaymentId], references: [id]) creditCardPaymentId String? @db.ObjectId // 移除@unique boletoPayment Payment? @relation(name: "boletoPayment", fields: [boletoPaymentId], references: [id]) boletoPaymentId String? @db.ObjectId // 移除@unique total Float createdAt DateTime @default(now()) @@map("Orders") }
修改后重新运行prisma migrate dev更新数据库,就能正常创建多个未关联支付的Order。
方案2:使用稀疏索引保留唯一约束
如果必须保留字段的唯一约束,但允许多个null值,可以通过稀疏索引实现。稀疏索引会忽略字段值为null的文档,只对有值的条目做唯一性校验:
model Order { id String @id @default(auto()) @map("_id") @db.ObjectId customer User @relation(fields: [customerId], references: [id]) customerId String @db.ObjectId products Json status String @default("pending") paymentMethod String? pixPayment Payment? @relation(name: "pixPayment", fields: [pixPaymentId], references: [id]) pixPaymentId String? @unique @db.ObjectId creditCardPayment Payment? @relation(name: "creditCardPayment", fields: [creditCardPaymentId], references: [id]) creditCardPaymentId String? @unique @db.ObjectId boletoPayment Payment? @relation(name: "boletoPayment", fields: [boletoPaymentId], references: [id]) boletoPaymentId String? @unique @db.ObjectId total Float createdAt DateTime @default(now()) // 为每个可选唯一字段添加稀疏索引 @@index([pixPaymentId], sparse: true) @@index([creditCardPaymentId], sparse: true) @@index([boletoPaymentId], sparse: true) @@map("Orders") }
同样需要运行prisma migrate dev将索引变更同步到数据库,之后未设置支付ID的Order可以正常创建,而当设置了支付ID时,依然会保证全局唯一性。
内容的提问来源于stack exchange,提问作者Brunosvx
相关产品推荐
相关产品推荐

