如何通过Rails查询translations表中jsonb字段的未翻译记录?
嘿,我来帮你解决这个PostgreSQL jsonb字段的查询问题!你要找translations表里values字段中存在未翻译(空字符串)的记录,之前的写法没用到PostgreSQL对jsonb的原生支持,所以没生效。下面分几种常见场景给你靠谱的解决方案:
解决方案
1. 查找任意语言翻译为空的记录
这是最常见的需求——只要某个语言的翻译是空字符串,就返回这条记录。我们可以用PostgreSQL的jsonb_each_text函数把jsonb字段拆成键值对行,再结合EXISTS子查询过滤:
Translation.where(<<~SQL) EXISTS ( SELECT 1 FROM jsonb_each_text(values) AS t(lang, text) WHERE t.text = '' ) SQL
这个查询的逻辑是:遍历每条Translation的values字段,把它拆成「语言-文本」的行数据,只要其中有任意一行文本是空字符串,就把这条Translation记录选出来。
2. 查找特定语言翻译为空的记录
如果你只关心某个特定语言(比如英文en)的空翻译,写法会更简单:
直接写SQL字符串
Translation.where("values ->> 'en' = ''")
这里的->>是PostgreSQL的jsonb操作符,用来提取指定键的文本值,然后判断是否等于空字符串。
更安全的Arel写法(适合语言是变量的场景)
如果语言是动态传入的,用Arel可以避免SQL注入问题:
target_lang = 'en' # 可以是任意变量 Translation.where(Translation.arel_table[:values].get_text(target_lang).eq(''))
3. 查找所有语言都未翻译的记录
如果要找那些values里所有语言的翻译都是空字符串的记录,可以用反向的EXISTS查询:
Translation.where(<<~SQL) NOT EXISTS ( SELECT 1 FROM jsonb_each_text(values) AS t(lang, text) WHERE t.text != '' ) SQL
意思是:如果这条记录的values里找不到任何非空的翻译文本,就把它选出来。
为什么你之前的写法不对?
- 你尝试的
Translation.where(values.values=""):ActiveRecord会把values.values当成SQL的一部分,但PostgreSQL根本不认识这个语法,自然会报错。 - 你写的循环遍历
Translation.all.values.each:这种方法会把所有Translation记录加载到内存里再遍历,数据量小的时候还行,但数据量大的时候会严重影响性能,而且代码逻辑也没必要这么复杂,直接用数据库查询高效得多。
内容的提问来源于stack exchange,提问作者Arb
相关产品推荐
相关产品推荐

