使用匹配的键将数组推入Laravel集合

时间:2016-01-06 00:33:14

标签: php arrays laravel laravel-5

我有一个名为User的集合,我还有一个数组,其中包含与Post模型相关的两个模型User

User集合包含主键id,我的Post集合中的每个模型都有一个外键user_id

我目前正在执行以下操作:

foreach ($users as $user) {
    foreach ($posts as $post) {
        if ($post->user_id == $user->id) {
            $user->posts->push($post);
        }
    }
}

这有点奏效,但并不完全是因为它提取了所有相关帖子,而不是用户最近的两个帖子。

数组如下所示:

enter image description here

我的User架构看起来像;与Post的hasMany关系:

enter image description here

3 个答案:

答案 0 :(得分:3)

您可以使用User加载与with相关联的帖子,例如

$user = User::with('posts')->find($id);

但您的情况听起来特别收集属于Post的最新两个User。要限制结果,您还可以使用范围。

Post模型上的以下内容可行:

public function scopeLatest($query, $latest = 2)
{
    return $query->limit($latest);
}

然后通过以下方式收集这些:

// The user record.
$user = User::find($id);

// Latest 2 posts for this user.
$posts = $user->posts()->latest();

// Latest 5 posts for this user.
$posts = $user->posts()->latest(5);

但是,如果您要在一个查询中加载最新的2个帖子,那么您可以建立新关系:

public function latestPosts()
{
    return $this->hasMany(Post::class,  'post_id', 'id') 
        ->orderBy('created_at', 'ASC')
        ->limit(2);
}

这可以通过以下方式工作:

// Load the user with the latest 2 posts.
$user = User::with('latestPosts')->find($userId);

// Access these using; this will be a Collection containing 2 `Post` records.
dd($user->latestPosts);

基本上使用Eloquent,当你调用$this->latestPosts时,Eloquent会运行latestPosts()并保存相关记录。使用with这种水合作用只需一个查询即可,并且已经定义了关系。

方法latestPosts()和属性$latestPosts之间的区别很简单。

该方法将始终返回特定的Relation Collection,允许您链接其他条件;

所以:$user->latestPosts()->get()$user->latestPosts相同。

答案 1 :(得分:1)

您不能使用查询约束/预先加载来执行此操作。这样做只有在您检索一个用户的帖子时才有效。但是,如果您尝试检索多个用户的帖子,它将失败,因为急切的加载/查询约束将限制整个相关结果。要理解,您必须查看Eloquent生成的查询。让我们来看一个你只需要一个用户帖子的例子。

$user = User::with(['posts' => function($query) {
    $query->limit(2);
}])->find(1);

在这个例子中,我们得到一个主键为1的用户。我们还检索他/她的帖子,但限制它,所以我们只检索2个帖子。这是有效的,它将生成2个类似于此的查询:

select * from `users` where `users`.`id` = 1 limit 1
select * from `posts` where `posts`.`user_id` in (1) limit 2

好。现在,如果你试图获得超过1个用户(或一组用户),为什么这不起作用?例如:

$user = User::with(['posts' => function($query) {
    $query->limit(2);
}])->get();

在这种情况下,我将find(1)更改为get(),它会生成2个这样的查询:

select * from `users`
select * from `posts` where `posts`.`user_id` in (?, ?, ?, ... ?) limit 2

重要的是看一下第二个查询。它正在检索所有相关帖子,但最后,您会看到它有limit 2。换句话说,它将整个相关集合限制为仅2,这就是为什么查询约束不适用于此。

实现这一点实际上非常复杂,但是其他成员(Jarek Tkaczyk)提出了使用MySQL变量的解决方案,您可以在此处找到:Laravel - Limit each child item efficiently

答案 2 :(得分:0)

使用https://laravel.com/docs/5.2/eloquent-relationships#eager-loading约束可以更简单一些。

示例:用户有很多狗,但只有2个

    $user = App\User::with(['dogs'  => function ($query) {
        $query->limit(2);
    }])->find($user_id);

    dump($user);

匿名约束函数在你的情况下也会有一个orderBy