简体   繁体   English

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

[英]Push an array into Laravel collection with matching keys

I have a collection called User , I also have an array containing two models Post relating to the User model. 我有一个名为User的集合,我也有一个包含两个模型的数组,其中两个PostUser模型有关。

The User collection contains a primary key id and each model in my Post collection I have a foreign key user_id . User集合包含一个主键id而我的Post集合中的每个模型都有一个外键user_id

I am currently executing the following: 我目前正在执行以下操作:

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

This somewhat works, but not entirely because it pulls in all related posts instead of the recent two posts a user has made. 这多少有些奏效,但并不完全是因为它提取了所有相关帖子,而不是用户最近发表的两个帖子。


The array looks like the following: 该数组如下所示:

在此处输入图片说明

My User schema looks like; 我的User架构看起来像; with a hasMany relationship to Post : Post有hasMany关系:

在此处输入图片说明

You can load the posts associated to a User using with , something like 您可以装入关联到一个职位User使用with ,类似

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

But your scenario sounds specifically collecting the latest two Post belonging to a User . 但是您的场景听起来特别是收集了属于User的最新两个Post To limit your results you can also use scopes. 为了限制结果,您还可以使用范围。

Something like the following on your Post model would work: Post模型上的以下内容将起作用:

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

Then collect these by: 然后通过以下方式收集这些:

// 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);

However, should you with to load the latest 2 posts with the user in a single query - then you could make a new relation: 但是,如果您要在单个查询中向用户加载最新的2条帖子,那么您可以建立新的关系:

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

This would work in the following way: 这将以以下方式工作:

// 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);

Basically with Eloquent, when you call $this->latestPosts Eloquent will run latestPosts() and hydrate the related records. 基本上,对于Eloquent,当您调用$this->latestPosts将运行latestPosts()latestPosts()相关记录。 Using with this hydration occurs with a single query and the relations are already defined. with这种水合一起使用仅需一个查询,并且关系已经定义。

The difference between the method latestPosts() and the property $latestPosts is simple. 方法latestPosts()和属性$latestPosts之间的$latestPosts很简单。

The method will always return a specific Relation Collection allowing you to chain additional conditions; 该方法将始终返回一个特定的Relation Collection,使您可以链接其他条件。

So: $user->latestPosts()->get() is the same as $user->latestPosts . 因此: $user->latestPosts()->get()$user->latestPosts相同。

You cannot use query constraints / eager loading to do this. 您不能使用查询约束/急切加载来执行此操作。 Doing so will only work if you are retrieving the posts for one user. 仅当您要检索一位用户的帖子时,此方法才起作用。 However, if you try to retrieve the posts for multiple users, it will fail because eager loading / query constraints will limit the related results as a whole. 但是,如果您尝试检索多个用户的帖子,则将失败,因为急切的加载/查询约束将限制整个相关结果。 To understand, you have to look at the queries Eloquent generates. 要理解,您必须查看Eloquent生成的查询。 Lets take a look at an example where you only need one user's posts. 让我们看一个仅需要一个用户帖子的示例。

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

In this example, we are getting a user with a primary key of 1. We also also retrieving his/her posts but limiting it so we only retrieve 2 posts. 在此示例中,我们获得一个主键为1的用户。我们还检索了他/她的帖子,但对其进行了限制,因此我们只检索2个帖子。 This works, and it will generate 2 queries similar to this: 这可行,并且将生成2个与此类似的查询:

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

Okay. 好的。 Now, why doesn't this work if you try to get more than 1 user (or a collection of users)? 现在,如果您尝试获得1个以上的用户(或一组用户),为什么此方法不起作用? For example: 例如:

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

In this case, I changed find(1) to get() , and it will generate 2 queries like this: 在这种情况下,我将find(1)更改为get() ,它将生成如下两个查询:

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

It's important to take a look at the second query. 查看第二个查询很重要。 It's retrieving all the related posts, but at the end, you'll see that it has limit 2 . 它正在检索所有相关的帖子,但是最后,您会看到它的limit 2 In other words, it's limiting the entire related collection to only 2, which is why query constraints do not work for this. 换句话说,它将整个相关集合限制为2个,这就是为什么查询约束对此不起作用的原因。

Achieving this is actually pretty complex, but a fellow member ( Jarek Tkaczyk ) came up with a solution using MySQL variables, which you can find here: Laravel - Limit each child item efficiently 实现这一点实际上很复杂,但是一个成员( Jarek Tkaczyk )提出了一个使用MySQL变量的解决方案,您可以在这里找到: Laravel-有效地限制每个子项

You can do this a bit simpler with https://laravel.com/docs/5.2/eloquent-relationships#eager-loading constraints. 您可以使用https://laravel.com/docs/5.2/eloquent-relationships#eager-loading约束来简化操作。

Example: Users have many Dogs, but only take 2 示例:用户有很多狗,但只带2条

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

    dump($user);

The anonymous constraining function would also have an orderBy in your case 匿名约束函数在您的情况下也将具有orderBy

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM