Laravel Collection按单个语言维度分组统计及内部排序方案咨询
解决方案:按单个语言维度统计并排序
我明白你的需求——你需要统计每个单独语言(比如en、ar)在所有用户中的出现次数,而不是按整个languages JSON字符串分组。这里有两种靠谱的解决方案,你可以根据场景选择:
方法一:利用Laravel Collection处理(推荐,简单直接)
既然你已经有了Illuminate\Support\Collection实例,直接在内存中处理是最快捷的方式,不需要依赖数据库的JSON功能版本:
// 假设你的Collection实例是$userCollection $languageStats = $userCollection // 遍历每个用户,解析JSON并提取所有语言的键(比如en、cy) ->flatMap(function ($user) { $languages = json_decode($user->languages, true); // 返回语言键数组,flatMap会自动把所有数组合并成一个扁平数组 return array_keys($languages); }) // 统计每个语言的出现次数 ->countBy() // 按出现次数降序排序(升序用sortAsc()) ->sortDesc();
代码解释:
flatMap():遍历集合中的每个用户,解析languagesJSON字符串为关联数组,然后提取所有语言的键(因为我们只需要统计语言出现次数,不需要关注熟练度),最后把所有用户的语言键合并成一个单一数组。countBy():自动统计数组中每个语言的出现次数,返回一个键为语言代码、值为次数的集合。sortDesc():按次数从高到低排序,方便查看热门语言。
执行后你会得到类似这样的结果:
Illuminate\Support\Collection {#3272 #items: array:8 [ "en" => 66 "cy" => 24 "ar" => 66 "eo" => 66 // ...其他语言的统计结果 ] }
方法二:数据库层面处理(适合大数据量场景)
如果你的数据量非常大(比如上万条),在数据库层面展开JSON并统计性能会更好。不过需要注意数据库版本:
MySQL 8.0.4+ 版本
利用JSON_TABLE函数展开JSON对象的键:
$languageStats = User::whereIn('id', $services_id) ->selectRaw('lang, COUNT(*) as occurrence_count') ->fromSub(function ($query) use ($services_id) { $query->selectRaw('JSON_TABLE( user_info->>"$.languages", "$.*" COLUMNS (lang VARCHAR(50) PATH "$.key") ) AS langs') ->from('users') ->whereIn('id', $services_id); }, 'user_languages') ->groupBy('lang') ->orderBy('occurrence_count', 'desc') ->get();
PostgreSQL 版本
利用jsonb_each_text函数拆分JSON对象:
$languageStats = User::whereIn('id', $services_id) ->selectRaw('lang, COUNT(*) as occurrence_count') ->fromSub(function ($query) use ($services_id) { $query->selectRaw('jsonb_each_text(user_info->\'languages\') AS (lang, proficiency)') ->from('users') ->whereIn('id', $services_id); }, 'user_languages') ->groupBy('lang') ->orderBy('occurrence_count', 'desc') ->get();
方法二说明
这种方式直接在数据库中完成JSON解析、拆分和统计,避免了把大量数据加载到内存中,适合数据量较大的场景。但需要确保你的数据库版本支持对应的JSON函数。
内容的提问来源于stack exchange,提问作者Ghiath Al-Khatib
相关产品推荐
相关产品推荐

