Slick过滤Rep[Seq[T]]:Play! Scala项目jsonb数组查询问题
嘿,刚好碰到过类似的场景,给你分享个高效的解法,不用再挨个遍历test2的元素啦~
解决Slick查询PostgreSQL jsonb数组中满足条件的行
首先得明确:PostgreSQL本身对jsonb有很强的原生支持,咱们不用在代码里手动遍历数组元素,直接让数据库帮咱们做过滤,既简洁又高效。
核心思路
你的需求是筛选config->test2数组中至少有一个元素的bool字段为true的行,PostgreSQL提供了两种靠谱的实现方式:
- 使用
jsonb_path_exists路径查询(PostgreSQL 12+支持,最简洁) - 结合
jsonb_array_elements展开数组做子查询(兼容旧版本PostgreSQL)
下面结合Slick来具体实现:
前提假设
假设你的表定义大概是这样(基于Play的Json类型,搭配Slick的PostgreSQL支持):
import play.api.libs.json.Json import slick.jdbc.PostgresProfile.api._ case class YourEntity(id: Long, config: Json) class YourTable(tag: Tag) extends Table[YourEntity](tag, "your_table") { def id = column[Long]("id", O.PrimaryKey, O.AutoInc) def config = column[Json]("config") // Play-Slick通常会自动处理Json与jsonb的隐式映射 def * = (id, config) <> (YourEntity.tupled, YourEntity.unapply) } val yourTableQuery = TableQuery[YourTable]
方法1:用jsonb_path_exists(推荐)
这个方法直接用PostgreSQL的JSON路径表达式,一行就能搞定过滤,而且数据库可以利用jsonb索引(如果你创建了的话):
val filterQuery = yourTableQuery.filter { row => // 自定义Slick表达式,生成jsonb_path_exists的SQL语句 SimpleExpression.bool[Json]( (configCol, queryBuilder) => { queryBuilder += "jsonb_path_exists(" queryBuilder.expr(configCol) queryBuilder += ", '$.test2[*].bool ? (@ == true)')" } ).apply(row.config) } // 执行查询(db是你的Slick Database实例) val result: Future[Seq[YourEntity]] = db.run(filterQuery.result)
这里的路径表达式$.test2[*].bool ? (@ == true)意思是:遍历test2数组的所有元素,检查是否存在元素的bool字段等于true。
方法2:用jsonb_array_elements子查询(兼容旧版PG)
如果你的PostgreSQL版本低于12,用这种方式更稳妥:
val filterQuery = yourTableQuery.filter { row => // 子查询:展开test2数组,检查是否有元素的bool为true exists( sql"""SELECT 1 FROM jsonb_array_elements(${row.config}->'test2') elem WHERE elem->>'bool' = 'true'""" .as[Int] .take(1) ) }
这个子查询会把test2数组展开成多行,只要有一行满足bool='true',就会返回1,外层的exists就会判定为true,从而筛选出目标行。
为什么不要挨个遍历元素?
你之前尝试的逐个检查test2[0]、test2[1]...有三个明显的问题:
- 代码冗余:test2有10个元素就要写10个OR条件,维护起来太麻烦
- 扩展性差:如果以后test2的元素数量变化,代码就得跟着修改
- 效率低:数据库要逐个检查每个元素,而上面的两种方法都是数据库优化过的,尤其是路径查询可以利用jsonb索引,查询速度快很多
额外优化:给jsonb列建索引
如果这个查询很频繁,建议给config列建个jsonb路径索引,进一步提升查询速度:
CREATE INDEX idx_config_test2_bool ON your_table USING gin (config jsonb_path_ops);
内容的提问来源于stack exchange,提问作者Scaum
相关产品推荐
相关产品推荐

