Prisma使用array_contains过滤JSON数组报JsonNullableFilter类型错误
错误产生原因
array_contains是Prisma为原生数据库数组类型(比如PostgreSQL的String[]、Int[]标量数组字段)设计的过滤操作符,默认不会绑定到Json/Json?(可空JSON类型,对应报错中的JsonNullableFilter类型)字段上。- 触发这个报错的核心原因是:你在Schema中将存储数组的字段定义为了JSON类型,Prisma的类型校验层严格按照Schema声明的字段类型匹配可用操作符,不会因为JSON字段里实际存的是数组值就放开数组操作符的使用权限,直接调用就会抛出类型错误。
- 新手常见踩坑点:建表时为了省事故意用JSON类型存数组,误以为值是数组就可以直接用数组类过滤语法。
正确解决方法
根据实际场景二选一即可:
方案1:改字段为原生数组类型(长期推荐,仅支持PostgreSQL等兼容原生数组的数据库)
这是性能、类型安全性最好的方案:
- 修改
schema.prisma中的字段定义,把原来的JSON类型改成对应数据类型的原生数组,比如存字符串标签数组就写String[],存数字ID数组就写Int[]:
model Record { id Int @id @default(autoincrement()) // 错误的原写法:tagList Json? tagList String[] // 改为原生字符串数组类型 }
- 执行
npx prisma migrate dev生成并执行数据库迁移,同步表结构。 - 之后就可以正常使用
array_contains做过滤,不会再触发报错:
const res = await prisma.record.findMany({ where: { tagList: { array_contains: ["Node.js"] } } })
方案2:保留JSON字段类型,调整过滤写法(适合暂时无法改表结构的场景)
如果因为数据库不支持原生数组(比如MySQL、SQLite)或者其他原因必须保留JSON字段,不要直接在JSON字段上裸用array_contains:
- 如果是PostgreSQL环境,显式传入
path参数指定要检查的JSON路径:根节点直接为数组时传'$'即可;如果数组是JSON结构下的某个属性(比如字段值为{ tags: ["a", "b"] }),传入对应路径如'$.tags':
// 根节点是数组的场景 const res = await prisma.record.findMany({ where: { tagList: { path: '$', // 声明检查JSON根节点的内容 array_contains: ["Node.js"] } } }) // 数组是JSON内部属性的场景 const res2 = await prisma.record.findMany({ where: { extraConfig: { // extraConfig是Json类型,存储结构为{ tags: ["a", "b"] } path: '$.tags', array_contains: ["Node.js"] } } })
- 如果是MySQL、SQLite等不支持上述JSON数组操作语法的环境,用原生查询兜底实现:
// MySQL 环境示例 const targetTag = "Node.js" const res = await prisma.$queryRaw` SELECT * FROM Record WHERE JSON_CONTAINS(tagList, JSON_ARRAY(${targetTag})) `
注意:JSON字段存数组的写法无法利用原生数组的索引优化,大数据量下查询性能会明显差于原生数组字段,有条件优先选择方案1。
内容的提问来源于stack exchange,提问作者Pawan Verma
相关产品推荐
相关产品推荐

