使用laravel-translatable无法查询指定语言博客记录求助
Laravel-Translatable 查询包含指定语言翻译的记录(MariaDB)
问题场景
使用laravel-translatable开发无前端API多语言系统,需查询blog表中**标题字段包含指定语言(如英文en、法文fr)**的记录,尝试的几种内存过滤/未定义方法均无法解决问题。
核心问题分析
你之前的尝试存在以下问题:
- 方法1:
DB::table()->get()返回的是stdClass对象,并非Eloquent模型实例,不存在getTranslations方法,直接报错。 - 方法2:先拉取全表数据到内存再过滤,数据量大时内存占用过高、性能极差。
- 方法3:
titleEqualsEn()是未定义的自定义查询范围,自然无法执行。
正确解决方案(数据库层面直接查询,推荐)
利用MariaDB原生的JSON函数JSON_CONTAINS_PATH,直接在数据库层筛选符合条件的记录,避免内存浪费。
1. 查询包含单一语言的记录
Route::get('/', function () { $blogs = DB::table('blogs') // 检查title字段是否包含en键 ->whereRaw("JSON_CONTAINS_PATH(title, 'one', '$.en')") ->get(); return response()->json($blogs); });
参数说明:
'one':只要存在指定键中的任意一个即满足条件'$.en':JSON路径,代表根节点下的en字段
2. 查询同时包含多种语言的记录
Route::get('/', function () { $blogs = DB::table('blogs') // 必须同时包含en和fr键 ->whereRaw("JSON_CONTAINS_PATH(title, 'all', '$.en', '$.fr')") ->get(); return response()->json($blogs); });
参数说明:
'all':必须满足所有指定键的存在条件
基于Eloquent模型的优化方案
如果使用Eloquent模型(配合laravel-translatable的HasTranslations trait),可以封装查询范围方便复用:
第一步:确保模型配置正确
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Spatie\Translatable\HasTranslations; class Blog extends Model { use HasTranslations; // 定义需要翻译的字段 public $translatable = ['title', 'content']; }
第二步:添加自定义查询范围
在Blog模型中添加:
/** * 筛选指定字段包含所有指定语言翻译的记录 * @param \Illuminate\Database\Eloquent\Builder $query * @param string $field 要检查的字段名 * @param array $languages 语言码数组 * @return \Illuminate\Database\Eloquent\Builder */ public function scopeHasAllTranslations($query, $field, array $languages) { $jsonPaths = collect($languages)->map(fn($lang) => "'$.$lang'")->implode(', '); return $query->whereRaw("JSON_CONTAINS_PATH($field, 'all', $jsonPaths)"); }
第三步:使用查询范围
Route::get('/', function () { // 查询标题同时包含英文和法文的博客 $blogs = Blog::hasAllTranslations('title', ['en', 'fr'])->get(); return response()->json($blogs); });
内容的提问来源于stack exchange,提问作者DolDurma
相关产品推荐
相关产品推荐

