Laravelコレクションから特定の属性のみを取得する


84

LaravelコレクションのドキュメントとAPIを確認していますが、探しているものが見つからないようです。

コレクションからモデルデータを含む配列を取得したいのですが、指定された属性のみを取得します。

以下のようなIEの何かUsers::toArray('id','name','email')、彼らは別の場所で使用されているが、この特定の場所で、私はユーザデータを配列し、唯一の指定された属性を必要とするので、実際にコレクションは、ユーザーのすべての属性を保持しています、。

Laravelにはこれを助けるものがないようですか?-これを最も簡単な方法で行うにはどうすればよいですか?


他の視聴者はに興味があるかもしれませんCollection::implode()。プロパティを取得して、コレクション内のすべてのオブジェクトから抽出できます。これはこの質問に正確に答えるものではありませんが、私が行ったように、Googleからここに来た他の人にとっては役立つかもしれません。laravel.com/docs/5.7/collections#method-implode
musicin3d

回答:


181

これは、既存の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な配列をプレーンな配列に戻します。

すべてをまとめると、「usersコレクション内のユーザーごとに、ID、名前、および電子メール属性のみの配列を返します」というメッセージが表示されます。


Laravel5.5アップデート

Laravel 5.5onlyは、モデルにメソッドを追加しました。これは基本的にと同じことを行う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']);
});

これをLaravel5.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 2016

それでおしまい。しかし、QueryBuilderの::get([ 'fields', 'array' ])動作をエミュレートするための冗長でない方法があればいいのにと思います。基本的には「ダンプ」に便利です。
pilat 2018年

実行できるアレイの場合$newArray = Arr::only($initialArray, [ 'id', 'name' /* allowed keys list */ ]);
ホップホップ

これは素晴らしいことですが、ネストされた配列が内部にある場合、どのように機能するのでしょうか
18

1
Laravelの最近のバージョンでは、これは、より簡潔に書くことができます:$users->map->only(['column', ...])
okdewit

17

を使用するUser::get(['id', 'name', 'email'])と、指定された列を持つコレクションが返されます。配列にしたい場合は、次のようなメソッドのtoArray()後に使用してget()ください。

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

コレクションは実際にはステロイド上の配列であり、コレクションを操作するための使いやすいメソッドがあるため、ほとんどの場合、コレクションを配列に変換する必要はありません。


1
コレクションは、より多くの属性が必要な前のクエリによってすでに作成されています。したがって、特定の属性のみを持つデータ配列を生成する必要があります。
preyz 2016

返す列の配列を渡してクエリを動的にするか->get(['id', 'email', 'name'])、データベースを再クエリしないが、選択した値のみを含む新しいコレクションを返す別のクエリを実行できます。pluck / list、get、firstなどのメソッドは、クエリビルダークラスとコレクションクラスの両方で同じ名前を持っています。
Davor Minchorov 2016

Laravel5.3では機能しないフリル。-クエリビルダーの「get」メソッドは実際には列を取りますが、別のクエリも実行します。コレクションの「get」メソッドは、コレクションからキーによって特定のモデルを抽出できますが、これは私がここで求めているものではありません。
preyz 2016

get()は常にコレクションを返します。DB:: table()-> get()であるかModel :: get()であるかは関係ありません。したがって、クエリを変数に保存して、その上でgetメソッドを実行すると$ query変数、データベースへの別のクエリを取得しないでください。
Davor Minchorov 2016

1
$ query = Model :: where(...)のような変数にクエリを格納すると、$ query-> get()を実行するたびに、データベースへのクエリが実行されます。-また、あなたの提案は、問題の望ましい解決策ではありません。私はカスタムコレクションを介して実装したいくつかの新しい配列関数でそれを解決しました(私自身の答えを参照してください)。
preyz 2016

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.カスタムコレクションiLaravelを介して上記を実装します

$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
Andreas Hacker

0
  1. $hidden$visible属性を定義する必要があります。それらはグローバルに設定されます(つまり、常に$visible配列からすべての属性を返します)。

  2. メソッドmakeVisible($attribute)を使用すると、makeHidden($attribute)非表示と表示の属性を動的に変更できます。詳細:Eloquentシリアル化->プロパティの可視性を一時的に変更する


これをグローバルにしたくありませんが、コレクションから動的に抽出する属性を選択します。
preyz 2016

0

大きな配列から値を選択する必要があるという同様の問題がありましたが、結果のコレクションに単一の値の値のみを含める必要がありました。

pluck() この目的に使用できます(1つのキーアイテムのみが必要な場合)

を使用することもできますreduce()。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.