php 从 Laravel Collection 中仅获取特定属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38412091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get only specific attributes with from Laravel Collection
提问by preyz
I've been reviewing the documentation and API for Laravel Collections, but don't seem to find what I am looking for:
我一直在查看 Laravel Collections 的文档和 API,但似乎没有找到我要找的东西:
I would like to retrieve an array with model data from a collection, but only get specified attributes.
我想从集合中检索包含模型数据的数组,但只获取指定的属性。
I.e. something like Users::toArray('id','name','email')
, where the collection in fact holds all attributes for the users, because they are used elsewhere, but in this specific place I need an array with userdata, and only the specified attributes.
即类似的东西Users::toArray('id','name','email')
,其中集合实际上包含用户的所有属性,因为它们在其他地方使用,但在这个特定的地方,我需要一个包含用户数据的数组,并且只需要指定的属性。
There does not seem to be a helper for this in Laravel? - How can I do this the easiest way?
Laravel 中似乎没有这个帮手?- 我怎样才能以最简单的方式做到这一点?
回答by patricus
You can do this using a combination of existing Collection
methods. It may be a little hard to follow at first, but it should be easy enough to break down.
您可以使用现有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();
});
Explanation
解释
First, the map()
method basically just iterates through the Collection
, and passes each item in the Collection
to the passed in callback. The value returned from each call of the callback builds the new Collection
generated by the map()
method.
首先,该map()
方法基本上只是遍历Collection
,并将 中的每个项目Collection
传递给传入的回调。每次调用回调返回的值都会构建Collection
该map()
方法生成的新值。
collect($user->toArray())
is just building a new, temporary Collection
out of the Users
attributes.
collect($user->toArray())
只是新建一个,临时Collection
掉的Users
属性。
->only(['id', 'name', 'email'])
reduces the temporary Collection
down to only those attributes specified.
->only(['id', 'name', 'email'])
将临时Collection
减少到仅指定的那些属性。
->all()
turns the temporary Collection
back into a plain array.
->all()
将临时数据变Collection
回普通数组。
Put it all together and you get "For each user in the users collection, return an array of just the id, name, and email attributes."
把它们放在一起,你会得到“对于 users 集合中的每个用户,返回一个仅包含 id、name 和 email 属性的数组。”
Laravel 5.5 update
Laravel 5.5 更新
Laravel 5.5 added an only
method on the Model, which basically does the same thing as the collect($user->toArray())->only([...])->all()
, so this can be slightly simplified in 5.5+ to:
Laravel 5.5only
在 Model 上增加了一个方法,基本上和 做同样的事情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']);
});
If you combine this with the "higher order messaging" for collectionsintroduced in Laravel 5.4, it can be simplified even further:
如果将其与Laravel 5.4 中引入的集合的“高阶消息传递”结合起来,则可以进一步简化:
// 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']);
回答by Ruffles
use User::get(['id', 'name', 'email'])
, it will return you a collection with the specified columns and if you want to make it an array, just use toArray()
after the get()
method like so:
use User::get(['id', 'name', 'email'])
,它会返回一个包含指定列的集合,如果你想让它成为一个数组,只需toArray()
在get()
方法之后使用,如下所示:
User::get(['id', 'name', 'email'])->toArray()
User::get(['id', 'name', 'email'])->toArray()
Most of the times, you won't need to convert the collection to an array because collections are actually arrays on steroids and you have easy-to-use methods to manipulate the collection.
大多数时候,您不需要将集合转换为数组,因为集合实际上是类固醇上的数组,并且您有易于使用的方法来操作集合。
回答by hawx
Method below also works.
下面的方法也有效。
$users = User::all()->map(function ($user) {
return collect($user)->only(['id', 'name', 'email']);
});
回答by preyz
I have now come up with an own solution to this:
我现在想出了一个自己的解决方案:
1. Created a general function to extract specific attributes from arrays
1. 创建了一个通用函数来从数组中提取特定属性
The function below extract only specific attributes from an associative array, or an array of associative arrays (the last is what you get when doing $collection->toArray() in Laravel).
下面的函数仅从关联数组或关联数组数组中提取特定属性(最后一个是在 Laravel 中执行 $collection->toArray() 时得到的)。
It can be used like this:
它可以像这样使用:
$data = array_extract( $collection->toArray(), ['id','url'] );
I am using the following functions:
我正在使用以下功能:
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;
}
This solution does not focus on performance implications on looping through the collections in large datasets.
此解决方案不关注循环遍历大型数据集中的集合时的性能影响。
2. Implement the above via a custom collection i Laravel
2. 通过自定义集合 i Laravel 实现上述内容
Since I would like to be able to simply do $collection->extract('id','url');
on any collection object, I have implemented a custom collection class.
由于我希望能够简单地$collection->extract('id','url');
对任何集合对象进行操作,因此我实现了一个自定义集合类。
First I created a general Model, which extends the Eloquent model, but uses a different collection class. All you models need to extend this custom model, and not the Eloquent Model then.
首先我创建了一个通用模型,它扩展了 Eloquent 模型,但使用了不同的集合类。你所有的模型都需要扩展这个自定义模型,而不是 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 );
}
}
?>
Secondly I created the following custom collection class:
其次,我创建了以下自定义集合类:
<?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 );
}
}
?>
Lastly, all models should then extend your custom model instead, like such:
最后,所有模型都应该扩展您的自定义模型,如下所示:
<?php
namespace App\Models;
class Article extends Model
{
...
Now the functions from no. 1 above are neatly used by the collection to make the $collection->extract()
method available.
现在没有的功能。集合巧妙地使用了上面的 1 来使$collection->extract()
方法可用。
回答by Grzegorz Gajda
You need to define
$hidden
and$visible
attributes. They'll be set global (that means always return all attributes from$visible
array).Using method
makeVisible($attribute)
andmakeHidden($attribute)
you can dynamically change hidden and visible attributes. More: Eloquent: Serialization -> Temporarily Modifying Property Visibility
您需要定义
$hidden
和$visible
属性。它们将被设置为全局(这意味着总是从$visible
数组中返回所有属性)。使用方法
makeVisible($attribute)
,makeHidden($attribute)
您可以动态更改隐藏和可见属性。更多:雄辩:序列化 -> 临时修改属性可见性
回答by wired00
I had a similar issue where I needed to select values from a large array, but I wanted the resulting collection to only contain values of a single value.
我有一个类似的问题,我需要从一个大数组中选择值,但我希望结果集合只包含单个值的值。
pluck()
could be used for this purpose (if only 1 key item is required)
pluck()
可用于此目的(如果只需要 1 个关键项目)
you could also use reduce()
. Something like this with reduce:
你也可以使用reduce()
. 像这样的事情减少:
$result = $items->reduce(function($carry, $item) {
return $carry->push($item->getCode());
}, collect());
回答by abbood
this is a follow up on the patricus [answer][1] above but for nestedarrays:
这是对上面 patricus [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();
回答by NEM
$users = Users::get();
$subset = $users->map(function ($user) {
return array_only(user, ['id', 'name', 'email']);
});
回答by Luca C.
DB::table('roles')->pluck('title', 'name');
References: https://laravel.com/docs/5.8/queries#retrieving-results(search for pluck)
参考资料:https: //laravel.com/docs/5.8/queries#retrieving-results(搜索pluck)
回答by ken
this seems to work, but not sure if it's optimized for performance or not.
这似乎有效,但不确定它是否针对性能进行了优化。
$request->user()->get(['id'])->groupBy('id')->keys()->all();
$request->user()->get(['id'])->groupBy('id')->keys()->all();
output:
输出:
array:2 [
0 => 4
1 => 1
]