लारवेल कलेक्शन से केवल विशिष्ट विशेषताएँ प्राप्त करें


84

मैं लारवेल कलेक्शंस के लिए प्रलेखन और एपीआई की समीक्षा कर रहा हूं, लेकिन मुझे वह नहीं मिल रहा है जिसकी मुझे तलाश है:

मैं एक संग्रह से मॉडल डेटा के साथ एक सरणी को पुनः प्राप्त करना चाहूंगा, लेकिन केवल निर्दिष्ट विशेषताएँ प्राप्त करें।

यानी कुछ ऐसा Users::toArray('id','name','email'), जहां संग्रह वास्तव में उपयोगकर्ताओं के लिए सभी विशेषताओं को रखता है, क्योंकि वे कहीं और उपयोग किए जाते हैं, लेकिन इस विशिष्ट स्थान में मुझे उपयोगकर्ताडेटा के साथ एक सरणी की आवश्यकता होती है, और केवल निर्दिष्ट विशेषताएँ।

लारवेल में इसके लिए कोई सहायक नहीं लगता है? - मैं यह सबसे आसान तरीका कैसे कर सकता हूं?


अन्य दर्शकों में रुचि हो सकती है 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कॉलबैक में पारित होने के लिए प्रत्येक आइटम को पास करती है । कॉलबैक के प्रत्येक कॉल से लौटाया गया मान Collection, map()विधि द्वारा उत्पन्न नए को बनाता है ।

collect($user->toArray())अभी एक नया निर्माण कर रहा है, जो अस्थायी विशेषताओं से Collectionबाहर है Users

->only(['id', 'name', 'email'])Collectionउन विशेषताओं को निर्दिष्ट करने के लिए केवल अस्थायी रूप से कम करता है।

->all()एक अस्थायी Collectionसरणी में अस्थायी वापस जाता है।

यह सब एक साथ रखें और आपको "उपयोगकर्ता संग्रह में प्रत्येक उपयोगकर्ता के लिए, केवल आईडी, नाम और ईमेल विशेषताओं की एक सरणी लौटाएं।"


लारावेल 5.5 अपडेट

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

यदि आप इसे लारवेल 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']);

धन्यवाद! मैंने इसे स्वीकृत उत्तर के रूप में चिह्नित किया है, क्योंकि यह मौजूदा लारवेल कार्यक्षमता के साथ एक आकर्षण की तरह काम करता है। - अब, यह कस्टम संग्रह वर्ग के माध्यम से संग्रह को उपलब्ध कराया जा सकता है, जैसे कि मैंने अपने वैकल्पिक समाधान में वर्णित किया है।
प्रीज

बस। लेकिन मेरी इच्छा है कि QueryBuilder के ::get([ 'fields', 'array' ])व्यवहार का अनुकरण करने के लिए एक कम क्रिया तरीका था । मूल रूप से, यह "डंप" के लिए उपयोगी होगा।
पायलट

सरणियों के लिए आप कर सकते हैं$newArray = Arr::only($initialArray, [ 'id', 'name' /* allowed keys list */ ]);
हॉप हॉप

यह बहुत अच्छा है, लेकिन मुझे आश्चर्य है कि अगर मेरे अंदर एक नेस्टेड सरणी है तो यह कैसे काम कर सकता है
बजे

1
$users->map->only(['column', ...])
लारवेल के

17

उपयोग User::get(['id', 'name', 'email']), यह आपको निर्दिष्ट कॉलम के साथ एक संग्रह लौटाएगा और यदि आप इसे एक सरणी बनाना चाहते हैं, तो toArray()इस get()तरह से विधि के बाद उपयोग करें:

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

अधिकांश बार, आपको संग्रह को सरणी में बदलने की आवश्यकता नहीं होगी क्योंकि संग्रह वास्तव में स्टेरॉयड पर सरणियाँ हैं और आपके पास संग्रह में हेरफेर करने के लिए आसान-से-उपयोग के तरीके हैं।


1
संग्रह पहले से ही एक पिछली क्वेरी द्वारा बनाया गया है, जहां अधिक विशेषताओं की आवश्यकता है। इसलिए मुझे एक डेटा ऐरे जनरेट करना होगा जहाँ मेरे पास केवल विशिष्ट विशेषताएँ हों।
प्रियाज जूल

आप या तो लौटने के लिए कॉलम की एक सरणी को पारित करने के साथ अपनी क्वेरी को गतिशील बना सकते हैं या आप एक और कर सकते हैं ->get(['id', 'email', 'name'])जो डेटाबेस की आवश्यकता नहीं होगी लेकिन यह केवल चयनित मानों के साथ एक नया संग्रह लौटाएगा। प्लक / लिस्ट, मेथड, फर्स्ट आदि जैसे तरीकों में दोनों में एक ही नाम होता है, क्वेरी बिल्डर क्लास और कलेक्शन क्लास।
मांचोरोव जूल

रफल्स, कि लारवेल 5.3 में काम नहीं करता है। - क्वेरी बिल्डर "प्राप्त" विधि वास्तव में कॉलम लेती है, लेकिन यह एक और क्वेरी भी करती है। संग्रह की "प्राप्त" विधि संग्रह से कुंजी द्वारा एक विशिष्ट मॉडल निकाल सकती है, जो कि मैं यहां नहीं हूं।
प्रीज

get () हमेशा एक संग्रह लौटाता है, अगर यह DB :: table () -> get () या Model :: get () है, तो इससे कोई फर्क नहीं पड़ता, इसलिए यदि आप किसी चर में क्वेरी को सहेजते हैं और उस पर प्राप्त विधि को चलाते हैं। $ क्वेरी चर, आपको डेटाबेस के लिए एक और क्वेरी नहीं मिलनी चाहिए।
मांचोरोव जूल

1
जब मैं क्वेरी को $ क्वेरी = मॉडल :: कहां (...) जैसे चर में संग्रहीत करता हूं, तो यह डेटाबेस में एक क्वेरी चलाता है जब भी मैं $ क्वेरी करता हूं-> मिलता है ()। - इसके अलावा, अपने सुझाव imho समस्या के लिए एक वांछित समाधान नहीं है। मैंने इसे कुछ नए सरणी फ़ंक्शंस के साथ हल किया है जिन्हें मैंने कस्टम संग्रह के माध्यम से कार्यान्वित किया है (मेरा अपना उत्तर देखें)।
प्रियाज

3

नीचे विधि भी काम करती है।

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

1

मैं अब इसका खुद का हल लेकर आया हूं:

1. सरणियों से विशिष्ट विशेषताओं को निकालने के लिए एक सामान्य कार्य बनाया

एक साहचर्य सरणी, या साहचर्य सरणियों की एक सरणी से केवल विशिष्ट विशेषताएँ निकालने के नीचे का कार्य (अंतिम है जो आपको $ कलेक्शन करते समय मिलता है-> 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');किसी भी संग्रह वस्तु पर बस करने में सक्षम होना चाहता हूं, इसलिए मैंने एक कस्टम संग्रह वर्ग लागू किया है।

पहले मैंने एक सामान्य मॉडल बनाया, जो एलोकेंट मॉडल का विस्तार करता है, लेकिन एक अलग संग्रह वर्ग का उपयोग करता है। आप सभी मॉडल को इस कस्टम मॉडल का विस्तार करने की आवश्यकता है, न कि एलोकेंट मॉडल की।

<?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
{
...

अब नहीं से कार्य करता है। उपर्युक्त $collection->extract()विधि को उपलब्ध करने के लिए संग्रह द्वारा बड़े करीने से 1 का उपयोग किया जाता है ।


विस्तृत संग्रह पर लारवेल
एंड्रियास हैकर

0
  1. आपको परिभाषित करने $hiddenऔर $visibleविशेषताओं की आवश्यकता है । उन्हें वैश्विक सेट किया जाएगा (इसका मतलब है कि हमेशा सभी विशेषताओं को वापस लौटाएं$visible सरणी )।

  2. विधि का उपयोग करना makeVisible($attribute)और makeHidden($attribute)आप छिपी हुई और दृश्य विशेषताओं को गतिशील रूप से बदल सकते हैं। अधिक: वाक्पटु: क्रमबद्धता -> अस्थायी रूप से संशोधित संपत्ति दृश्यता


मैं नहीं चाहता कि यह वैश्विक हो, लेकिन संग्रह से निकालने के लिए विशेषताओं का चयन गतिशील रूप से करें।
प्रियाज़

0

मेरे पास एक समान मुद्दा था जहां मुझे एक बड़े सरणी से मानों का चयन करने की आवश्यकता थी, लेकिन मैं परिणामी संग्रह को केवल एक मूल्य के मूल्यों को शामिल करना चाहता था।

pluck() इस उद्देश्य के लिए इस्तेमाल किया जा सकता है (यदि केवल 1 कुंजी आइटम की आवश्यकता है)

आप भी उपयोग कर सकते हैं reduce()। कुछ इस तरह से कम करें:

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

0

यह पेट्रीक पर एक अनुवर्ती है [उत्तर] [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']);
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.