Laravel Koleksiyonundan sadece belirli özellikleri alın


84

Laravel Collections için belgeleri ve API'yi gözden geçiriyorum, ancak aradığımı bulamadım:

Bir koleksiyondan model verileri içeren bir dizi almak istiyorum, ancak yalnızca belirli öznitelikleri almak istiyorum.

Yani Users::toArray('id','name','email'), koleksiyonun aslında kullanıcılar için tüm öznitelikleri tuttuğu bir şey, çünkü bunlar başka bir yerde kullanılıyor, ancak bu belirli yerde, kullanıcı verilerini ve yalnızca belirtilen öznitelikleri içeren bir diziye ihtiyacım var.

Laravel'de bunun için bir yardımcı görünmüyor mu? - Bunu en kolay şekilde nasıl yapabilirim?


Diğer izleyiciler ilgilenebilir Collection::implode(). Bir özelliği alıp koleksiyondaki tüm nesnelerden çıkarabilir. Bu, bu soruyu tam olarak yanıtlamaz, ancak benim yaptığım gibi Google'dan buraya gelen başkaları için faydalı olabilir. laravel.com/docs/5.7/collections#method-implode
musicin3d

Yanıtlar:


181

Bunu, mevcut olanların bir kombinasyonunu kullanarak yapabilirsiniz. Collection yöntemlerin . İlk başta takip etmek biraz zor olabilir, ancak parçalanacak kadar kolay olmalıdır.

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

Açıklama

İlk olarak, map()yöntem temelde sadece yineler ve içindeki Collectionher öğeyi Collectiongeri aramada geçirilene geçirir . Geri aramanın her çağrısından döndürülen değer, Collectiontarafından oluşturulan yeniyi oluşturur.map() yöntem .

collect($user->toArray())sadece yeni, geçici bir şey inşa CollectionediyorUsers özniteliklerden .

->only(['id', 'name', 'email']) geçici azaltır Collection olanı yalnızca belirtilen özniteliklere .

->all()geçici Collectionolanı düz bir diziye dönüştürür.

Hepsini bir araya getirin ve "Kullanıcı koleksiyonundaki her kullanıcı için, yalnızca kimlik, ad ve e-posta özniteliklerinden oluşan bir dizi döndürün."


Laravel 5.5 güncellemesi

Laravel 5.5 only, Model üzerine temelde aynı şeyi yapan bir yöntem ekledi collect($user->toArray())->only([...])->all(), bu yüzden bu 5.5+ sürümünde biraz basitleştirilebilir:

// 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']);
});

Bunu Laravel 5.4'te sunulan koleksiyonlar için "daha yüksek sipariş mesajlaşma" ile birleştirirseniz, daha da basitleştirilebilir:

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

Teşekkürler! Bunu kabul edilen cevap olarak işaretledim, çünkü mevcut Laravel işlevselliğiyle bir cazibe gibi çalışıyor. - Şimdi, bu, alternatif çözümümde anlattığım gibi, özel bir koleksiyon sınıfı aracılığıyla koleksiyona sunulabilir.
preyz

Bu kadar. Ama QueryBuilder'ın ::get([ 'fields', 'array' ])davranışını taklit etmenin daha az ayrıntılı bir yolu olsaydı . Temel olarak, "dökümler" için kullanışlı olacaktır.
pilat

yapabileceğiniz diziler için$newArray = Arr::only($initialArray, [ 'id', 'name' /* allowed keys list */ ]);
Hop hop

bu harika ama iç içe geçmiş bir dizim varsa nasıl çalışacağını merak ediyorum
abbood

1
Laravel'in son sürümlerinde bu daha da kısa bir şekilde yazılabilir:$users->map->only(['column', ...])
okdewit

17

kullanım User::get(['id', 'name', 'email']), size belirtilen sütunlarla bir koleksiyon döndürür ve eğer onu bir dizi yapmak isterseniz, sadece aşağıdaki gibi yöntemden toArray()sonra kullanın get():

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

Çoğu zaman, koleksiyonları bir diziye dönüştürmeniz gerekmez çünkü koleksiyonlar aslında steroidler üzerindeki dizilerdir ve koleksiyonu değiştirmek için kullanımı kolay yöntemlere sahipsiniz.


1
Koleksiyon, daha fazla özniteliğin gerekli olduğu önceki bir sorgu tarafından zaten oluşturulmuştur. Bu nedenle, yalnızca belirli özelliklere sahip olduğum bir veri dizisi oluşturmam gerekiyor.
preyz

Ya sorgunuzu bir sütun dizisi döndürerek dinamik hale getirebilir ya ->get(['id', 'email', 'name'])da veritabanını yeniden sorgulamayacak ancak yalnızca seçilen değerlerle yeni bir koleksiyon döndürecek başka bir tane yapabilirsiniz. Pluck / list, get, first, vb. Yöntemler, sorgu oluşturucu sınıfında ve koleksiyon sınıfında aynı adlara sahiptir.
Davor Minchorov

Ruffles, Laravel 5.3'te çalışmıyor. - Sorgu oluşturucu "get" yöntemi aslında sütun alır, ancak başka bir sorgu da gerçekleştirir. Koleksiyonun "get" yöntemi, koleksiyondan belirli bir modeli anahtarla çıkarabilir, ki bu benim burada peşinde olduğum şey değil.
preyz

get () her zaman bir koleksiyon döndürür, DB :: table () -> get () veya Model :: get () olması önemli değildir, bu nedenle sorguyu bir değişkene kaydedip bunun üzerinde get yöntemini çalıştırırsanız $ sorgu değişkeni, veritabanına başka bir sorgu almamalısınız.
Davor Minchorov

1
Sorguyu $ query = Model :: where (...) gibi bir değişkende sakladığımda, her $ query-> get () yaptığımda veritabanına bir sorgu çalıştırıyor. - Ayrıca, imho öneriniz sorun için istenen bir çözüm değil. Özel bir koleksiyon aracılığıyla uyguladığım bazı yeni dizi işlevleriyle çözdüm (kendi cevabımı bul).
preyz

3

Aşağıdaki yöntem de işe yarar.

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

1

Şimdi buna kendi çözümüm var:

1. Dizilerden belirli öznitelikleri çıkarmak için genel bir işlev oluşturuldu

Aşağıdaki işlev, bir ilişkilendirilebilir diziden veya ilişkilendirilebilir dizilerden yalnızca belirli öznitelikleri çıkarır (sonuncusu Laravel'de $ collection-> toArray () işlemi yaparken elde ettiğiniz şeydir).

Şu şekilde kullanılabilir:

$data = array_extract( $collection->toArray(), ['id','url'] );

Aşağıdaki işlevleri kullanıyorum:

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;   
}

Bu çözüm, büyük veri kümelerinde koleksiyonlar arasında döngü oluşturmanın performans etkilerine odaklanmaz.

2. Yukarıdakileri özel bir koleksiyon yoluyla uygulayın i Laravel

Sadece yapabilmek istediğim için $collection->extract('id','url');Herhangi bir koleksiyon nesnesi üzerinde istediğim için, özel bir koleksiyon sınıfı uyguladım.

İlk olarak, Eloquent modelini genişleten, ancak farklı bir koleksiyon sınıfı kullanan genel bir Model oluşturdum. Tüm modellerin bu özel modeli genişletmesi gerekir, o zaman Eloquent Modeli değil.

<?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 );
    }    
}
?>

İkinci olarak, aşağıdaki özel koleksiyon sınıfını oluşturdum:

<?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 );
    }
}   
?>

Son olarak, tüm modeller bunun yerine özel modelinizi aşağıdaki gibi genişletmelidir:

<?php
namespace App\Models;
class Article extends Model
{
...

Şimdi hayır fonksiyonları. Yukarıdaki 1, $collection->extract()yöntemi kullanılabilir kılmak için koleksiyon tarafından özenle kullanılır .


Koleksiyonları genişletmek için Laravel belgelerine göz atın: laravel.com/docs/5.5/collections#extending-collections
Andreas Hacker

0
  1. Tanımlamanız $hiddenve $visiblenitelikleri belirlemeniz gerekir . Global olarak ayarlanırlar (bu, $visibledizideki tüm nitelikleri her zaman döndürmek anlamına gelir ).

  2. Yöntemi kullanarak makeVisible($attribute)ve makeHidden($attribute)dinamik gizli değişir edebilir ve görünür özellikler. Daha Fazla: Eloquent: Serileştirme -> Mülk Görünürlüğünü Geçici Olarak Değiştirme


Bunun global olmasını istemiyorum, ancak koleksiyondan dinamik olarak çıkarılacak öznitelikleri seçin.
preyz

0

Büyük bir diziden değer seçmem gereken benzer bir sorun yaşadım, ancak elde edilen koleksiyonun yalnızca tek bir değerin değerlerini içermesini istedim.

pluck() bu amaç için kullanılabilir (sadece 1 anahtar öğe gerekliyse)

ayrıca kullanabilirsiniz reduce(). İndirgeme ile bunun gibi bir şey:

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

0

bu, yukarıdaki patricus [cevap] [1] 'in devamıdır, ancak iç içe diziler için:

$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

bu işe yarıyor gibi görünüyor, ancak performans için optimize edilip edilmediğinden emin değil.

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

çıktı:

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

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

$subset = $users->map(function ($user) {
    return array_only(user, ['id', 'name', 'email']);
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.