我一直在审阅Laravel Collections的文档和API,但似乎找不到我想要的内容:
我想从集合中检索包含模型数据的数组,但只获取指定的属性。
即。像Users::toArray('id','name','email')
之类的东西,其中集合实际上包含用户的所有属性,因为它们在别处使用,但在这个特定的地方我需要一个带有userdata的数组,只有指定的属性。
在Laravel中似乎没有帮助吗? - 我怎样才能以最简单的方式做到这一点?
答案 0 :(得分:92)
您可以使用现有Collection
方法的组合来执行此操作。一开始可能有点难以理解,但它应该很容易打破。
// get your main collection with all the attributes...
$users = Users::get();
// build your second collection with a subset of attributes. this new
// collection will be a collection of plain arrays, not Users models.
$subset = $users->map(function ($user) {
return collect($user->toArray())
->only(['id', 'name', 'email'])
->all();
});
<强>解释强>
首先,map()
方法基本上只遍历Collection
,并将Collection
中的每个项目传递给传入的回调。每次回调调用返回的值都会构建Collection
方法生成的新map()
。
collect($user->toArray())
只是在Collection
属性中构建一个新的临时Users
。
->only(['id', 'name', 'email'])
将临时Collection
缩减为仅指定的属性。
->all()
将临时Collection
变回普通数组。
将所有内容放在一起,您就可以获得&#34;对于users集合中的每个用户,返回一个仅包含id,name和email属性的数组。&#34;
Laravel 5.5在模型上添加了一个only
方法,基本上和collect($user->toArray())->only([...])->all()
的方法相同,所以这可以在5.5+中略微简化为:
// get your main collection with all the attributes...
$users = Users::get();
// build your second collection with a subset of attributes. this new
// collection will be a collection of plain arrays, not Users models.
$subset = $users->map(function ($user) {
return $user->only(['id', 'name', 'email']);
});
如果将其与Laravel 5.4中引入的"higher order messaging" for collections结合使用,可以进一步简化:
// get your main collection with all the attributes...
$users = Users::get();
// build your second collection with a subset of attributes. this new
// collection will be a collection of plain arrays, not Users models.
$subset = $users->map->only(['id', 'name', 'email']);
答案 1 :(得分:11)
使用User::get(['id', 'name', 'email'])
,它会返回一个包含指定列的集合,如果你想让它成为一个数组,只需在toArray()
方法之后使用get()
,如下所示:
User::get(['id', 'name', 'email'])->toArray()
大多数情况下,您不需要将集合转换为数组,因为集合实际上是类固体上的数组,并且您可以使用易于使用的方法来操作集合。
答案 2 :(得分:3)
下面的方法也可以。
$users = User::all()->map(function ($user) {
return collect($user)->only(['id', 'name', 'email']);
});
答案 3 :(得分:1)
我现在想出了一个自己的解决方案:
<强> 1。创建了一个通用函数来从数组中提取特定属性
下面的函数只从关联数组或关联数组数组中提取特定属性(最后一个是在Laravel中执行$ collection-&gt; toArray()时得到的)。
可以像这样使用:
$data = array_extract( $collection->toArray(), ['id','url'] );
我正在使用以下功能:
function array_is_assoc( $array )
{
return is_array( $array ) && array_diff_key( $array, array_keys(array_keys($array)) );
}
function array_extract( $array, $attributes )
{
$data = [];
if ( array_is_assoc( $array ) )
{
foreach ( $attributes as $attribute )
{
$data[ $attribute ] = $array[ $attribute ];
}
}
else
{
foreach ( $array as $key => $values )
{
$data[ $key ] = [];
foreach ( $attributes as $attribute )
{
$data[ $key ][ $attribute ] = $values[ $attribute ];
}
}
}
return $data;
}
此解决方案不关注在大型数据集中循环遍历集合的性能影响。
<强> 2。通过自定义集合i Laravel
实现上述功能由于我希望能够对任何集合对象执行$collection->extract('id','url');
,因此我实现了自定义集合类。
首先,我创建了一个通用模型,它扩展了Eloquent模型,但使用了不同的集合类。所有模型都需要扩展此自定义模型,而不是扩展模型。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model as EloquentModel;
use Lib\Collection;
class Model extends EloquentModel
{
public function newCollection(array $models = [])
{
return new Collection( $models );
}
}
?>
其次,我创建了以下自定义集合类:
<?php
namespace Lib;
use Illuminate\Support\Collection as EloquentCollection;
class Collection extends EloquentCollection
{
public function extract()
{
$attributes = func_get_args();
return array_extract( $this->toArray(), $attributes );
}
}
?>
最后,所有模型都应该扩展您的自定义模型,例如:
<?php
namespace App\Models;
class Article extends Model
{
...
现在的功能从没有。集合巧妙地使用上面的1来使$collection->extract()
方法可用。
答案 4 :(得分:0)
您需要定义$hidden
和$visible
属性。它们将被设置为全局(这意味着始终返回$visible
数组中的所有属性)。
使用方法makeVisible($attribute)
和makeHidden($attribute)
,您可以动态更改隐藏和可见属性。更多:Eloquent: Serialization -> Temporarily Modifying Property Visibility
答案 5 :(得分:0)
我有一个类似的问题,我需要从大数组中选择值,但我希望结果集合只包含单个值的值。
pluck()
可用于此目的(如果只需要1个关键项)
你也可以使用reduce()
。像reduce这样的东西:
$result = $items->reduce(function($carry, $item) {
return $carry->push($item->getCode());
}, collect());
答案 6 :(得分:0)
这是对上面的父本[answer] [1]的后续操作,但对于嵌套数组:
$topLevelFields = ['id','status'];
$userFields = ['first_name','last_name','email','phone_number','op_city_id'];
return $onlineShoppers->map(function ($user) {
return collect($user)->only($topLevelFields)
->merge(collect($user['user'])->only($userFields))->all();
})->all();
答案 7 :(得分:0)
例如,假设您想显示一个用于在系统中创建新用户的表单,其中用户具有一个角色并且该角色可用于多个用户。
用户模型看起来像这样
class User extends Authenticatable
{
/**
* User attributes.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password', 'role_id'
];
/**
* Role of the user
*
* @return \App\Role
*/
public function role()
{
return $this->belongsTo(Role::class);
}
...
和角色模型
class Role extends Model
{
/**
* Role attributes.
*
* @var array
*/
protected $fillable = [
'name', 'description'
];
/**
* Users of the role
*
* @return void
*/
public function users()
{
return $this->hasMany(User::class);
}
}
在我们要创建的特定表单中,您需要来自 Role 的数据,但实际上并不需要描述。
/**
* Create user
*
* @param \App\Role $model
* @return \Illuminate\View\View
*/
public function create(Role $role)
{
return view('users.create', ['roles' => $role->get(['id', 'name'])]);
}
请注意,我们使用 $role->get(['id', 'name'])
来指定我们不需要描述。
答案 8 :(得分:-1)
这似乎有效,但不确定它是否针对性能进行了优化。
$request->user()->get(['id'])->groupBy('id')->keys()->all();
输出:
array:2 [
0 => 4
1 => 1
]
答案 9 :(得分:-1)
mutable_gpu_options()
答案 10 :(得分:-1)
DB::table('roles')->pluck('title', 'name');
参考文献:https://laravel.com/docs/5.8/queries#retrieving-results(寻找摘心)