Laravel基于数组匹配值排序雄辩集合


laravel sorting eloquent collection based on array matching values

我正在尝试构建一个项目推荐系统,其中用户和项目具有所需的技能标签。我正在尝试根据每个技能数组中匹配的技能数量为用户生成和排序推荐项目的集合,例如,与用户技能最匹配的项目将首先出现在推荐项目列表中。

这是我到目前为止的代码。

public function recommendedProjects()
{
    $projects = Project::all()->filter(function ($project) {
        foreach(unserialize($project->skills) as $projectSkill)
        {
            foreach(unserialize(Auth::user()->profile->skills) as $userSkill)
            {
                if($projectSkill === $userSkill)
                {
                    return true;
                }
            }
        }
    });
    return View::make('projects.projects')->with("title", "Recommended Projects")->with('projects', $projects);
}

到目前为止,它有点有效,但只返回具有至少一项匹配技能的项目。

如果我能将结果数量限制在最相关的 20 个左右的项目,也会有所帮助。

任何帮助都值得赞赏,这是我的第一个Laravel项目,哈哈。

编辑

我更改了我的代码以将技能存储在他们自己的表中,而不是使用序列化,现在它返回至少具有一个匹配用户技能的所有项目。

我想对项目进行排序,以便首先显示与用户技能最匹配的技能的项目。

例如,如果一个项目有 3 个必需技能,而用户拥有所有 3 个技能,则项目将首先出现在匹配技能较少的项目之上。

这是我更新的代码

  $projects = Project::all()->filter(function ($project) {
            foreach ($project->skills as $projectSkill) {
                foreach (Auth::user()->skills as $userSkill) {
                    if ($projectSkill->name === $userSkill->name) {
                        return true;
                    }
                }
            }
    });

您只需要对拥有的项目集合进行排序。试试这个:

$userSkills = Auth::user()->skills;
$projects = Projects::with('skills')->get();
$projects = $projects->sort(function($a, $b) use ($userSkills) {
    // Get the matching skills from both A and B
    $aMatchingSkills = $a->skills->intersect($userSkills);
    $bMatchingSkills = $b->skills->intersect($userSkills);
    // Return the count of A minus the count of B - See PHP uasort
    return $aMatchingSkills->count() - $bMatchingSkills->count();
});

这是相当广泛地使用雄辩的集合对象(sortintersectcount)。 sort 使用了 PHP 中一个非常有用的函数 - uasort

要删除没有匹配技能的项目,请尝试将Projects::with('skills')->get();位替换为...

Projects::with(['skills' => function($q) use ($userSkills) {
    $q->whereIn('name', $userSkills->fetch('name'));
}])->get();

现在这变得有点复杂,我不能保证我发布的内容会起作用,但它已经很接近了。