Laravel 컬렉션에서 특정 속성 만 가져옵니다.


83

Laravel Collections에 대한 문서와 API를 검토했지만 원하는 것을 찾지 못하는 것 같습니다.

컬렉션에서 모델 데이터가있는 배열을 검색하고 싶지만 지정된 속성 만 가져옵니다.

Users::toArray('id','name','email'), 컬렉션은 다른 곳에서 사용되기 때문에 실제로 사용자에 대한 모든 속성을 보유하지만이 특정 장소에서는 사용자 데이터가있는 배열과 지정된 속성 만 필요합니다.

라 라벨에 이것에 대한 도우미가없는 것 같습니까? -가장 쉬운 방법은 무엇입니까?


다른 시청자는에 관심이있을 수 있습니다 Collection::implode(). 속성을 가져와 컬렉션의 모든 개체에서 추출 할 수 있습니다. 이것은이 질문에 정확히 대답하지 않지만, 저처럼 Google에서 온 다른 사람들에게 유용 할 수 있습니다. laravel.com/docs/5.7/collections#method-implode
musicin3d

답변:


175

기존 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전달 된 콜백에 전달합니다. 콜백의 각 호출에서 반환 된 값 Collectionmap()메서드에 의해 생성 된 새 항목을 빌드합니다 .

collect($user->toArray())속성 에서 새롭고 일시적인 Collection것을 만드는 것입니다 Users.

->only(['id', 'name', 'email'])Collection지정된 속성 만 임시 로 줄 입니다.

->all()임시 Collection배열을 일반 배열로 되돌립니다.

모두 합치면 "사용자 컬렉션의 각 사용자에 대해 ID, 이름 및 이메일 속성의 배열 만 반환합니다."라는 메시지가 표시됩니다.


Laravel 5.5 업데이트

Laravel 5.5는 only기본적으로와 동일한 작업을 수행 하는 메서드를 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']);
});

이것을 라 라벨 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']);

감사! 기존 Laravel 기능과 함께 매력적으로 작동하기 때문에 나는 이것을 받아 들인 대답으로 표시했습니다. -이제 대체 솔루션에서 설명한 것처럼 사용자 지정 컬렉션 클래스를 통해 컬렉션에서 사용할 수 있습니다.
preyz jul.

그게 다야. 그러나 QueryBuilder의 ::get([ 'fields', 'array' ])동작 을 모방하는 덜 장황한 방법이 있었으면 합니다. 기본적으로 "덤프"에 유용합니다.
pilat

배열을 위해 당신이 할 수있는$newArray = Arr::only($initialArray, [ 'id', 'name' /* allowed keys list */ ]);
홉 홉

이 위대하지만 난 중첩 배열의 내부에있는 경우에 작동하는 방법을 궁금해
abbood

1
Laravel의 최신 버전에서는 더 간결하게 작성할 수 있습니다.$users->map->only(['column', ...])
okdewit

17

use User::get(['id', 'name', 'email']), 지정된 열이있는 컬렉션을 반환하고 배열로 만들려면 toArray()다음 get()과 같은 메서드 뒤에 사용 하십시오 .

User::get(['id', 'name', 'email'])->toArray()

대부분의 경우 컬렉션은 실제로 스테로이드의 배열이고 컬렉션을 조작하는 데 사용하기 쉬운 메서드가 있으므로 컬렉션을 배열로 변환 할 필요가 없습니다.


1
컬렉션은 더 많은 속성이 필요한 이전 쿼리에 의해 이미 생성되었습니다. 따라서 특정 속성 만있는 데이터 배열을 생성해야합니다.
preyz

반환 할 열 배열을 전달하여 쿼리를 동적으로 만들거나 ->get(['id', 'email', 'name'])데이터베이스를 다시 쿼리 하지 않는 다른 작업을 수행 할 수 있지만 선택한 값만 포함 된 새 컬렉션을 반환합니다. pluck / list, get, first 등과 같은 메서드는 쿼리 작성기 클래스와 컬렉션 클래스 모두에서 동일한 이름을 갖습니다.
Ruffles

Laravel 5.3에서 작동하지 않는 Ruffles. -쿼리 작성기 "get"메소드는 실제로 열을 사용하지만 다른 쿼리도 수행합니다. 컬렉션의 "get"메서드는 컬렉션에서 키로 특정 모델을 추출 할 수 있습니다. 이것은 제가 여기서 추구하는 것이 아닙니다.
preyz

get ()은 항상 컬렉션을 반환합니다. DB :: table ()-> get () 또는 Model :: get ()인지 여부는 중요하지 않으므로 쿼리를 변수에 저장하고 get 메서드를 실행하면 $ query 변수, 데이터베이스에 대한 다른 쿼리를 가져 오지 않아야합니다.
Ruffles

1
$ query = Model :: where (...)와 같은 변수에 쿼리를 저장하면 $ query-> get ()을 수행 할 때마다 데이터베이스에 대한 쿼리가 실행됩니다. -또한, 당신의 제안 imho는 문제에 대한 바람직한 해결책이 아닙니다. 사용자 지정 컬렉션을 통해 구현 한 새로운 배열 함수로 해결했습니다 (자신의 답변).
preyz

3

아래 방법도 작동합니다.

$users = User::all()->map(function ($user) {
  return collect($user)->only(['id', 'name', 'email']);
});

1

나는 이제 이것에 대한 자체 해결책을 생각해 냈습니다.

1. 배열에서 특정 속성을 추출하는 일반 함수 생성

아래 함수는 연관 배열 또는 연관 배열의 배열에서 특정 속성 만 추출합니다 (마지막은 Laravel에서 $ collection-> 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 모델을 확장하지만 다른 컬렉션 클래스를 사용하는 일반 모델을 만들었습니다. 모든 모델은 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()메서드를 사용할 수 있도록 깔끔하게 사용됩니다 .


확장 컬렉션에 Laravel 문서를 체크 아웃 : laravel.com/docs/5.5/collections#extending-collections
안드레아스 해커

0
  1. $hidden$visible속성 을 정의해야 합니다. 전역으로 설정됩니다 (즉, 항상 $visible배열 에서 모든 속성을 반환 함 ).

  2. 방법을 사용 makeVisible($attribute)하고 makeHidden($attribute)동적 숨겨진 변경하고 눈에 보이는 속성. 추가 : Eloquent : 직렬화-> 일시적으로 속성 가시성 수정


나는 이것이 전역 적이기를 원하지 않지만 컬렉션에서 동적으로 추출 할 속성을 선택합니다.
preyz

0

큰 배열에서 값을 선택해야하는 비슷한 문제가 있었지만 결과 컬렉션에 단일 값의 값만 포함되기를 원했습니다.

pluck() 이 용도로 사용할 수 있습니다 (단 하나의 키 항목 만 필요한 경우).

당신은 또한 사용할 수 있습니다 reduce(). 다음과 같이 축소하십시오.

$result = $items->reduce(function($carry, $item) {
    return $carry->push($item->getCode());
}, collect());

0

이것은 위의 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();


-1

이것은 작동하는 것처럼 보이지만 성능에 최적화되었는지 여부는 확실하지 않습니다.

$request->user()->get(['id'])->groupBy('id')->keys()->all();

산출:

array:2 [
  0 => 4
  1 => 1
]

-3
$users = Users::get();

$subset = $users->map(function ($user) {
    return array_only(user, ['id', 'name', 'email']);
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.