लारवेल: गुण द्वारा संग्रह से वस्तु प्राप्त करें


90

Laravel में, यदि मैं कोई क्वेरी करता हूं:

$foods = Food::where(...)->get();

...फिर $foods मॉडल वस्तुओं का एक प्रकाशित संग्रह है Food। (अनिवार्य रूप से मॉडल की एक सरणी।)

हालाँकि, इस सरणी की कुंजी बस हैं:

[0, 1, 2, 3, ...]

... इसलिए अगर मैं बदलना चाहता हूं, तो कहना है, एक Foodवस्तु के साथid 24 , मैं ऐसा नहीं कर सकता:

$desired_object = $foods->get(24);
$desired_object->color = 'Green';
$desired_object->save();

... क्योंकि यह केवल सरणी में 25 वें तत्व को बदल देगा, id24 के तत्व के साथ नहीं ।

मैं किसी भी विशेषता / कॉलम (जैसे, लेकिन आईडी / रंग / आयु / आदि तक सीमित नहीं) के संग्रह से एक (या एकाधिक) तत्व कैसे प्राप्त कर सकता हूं?

बेशक, मैं यह कर सकता हूं:

foreach ($foods as $food) {
    if ($food->id == 24) {
        $desired_object = $food;
        break;
    }
}
$desired_object->color = 'Green';
$desired_object->save();

... लेकिन, यह सिर्फ सकल है।

और, निश्चित रूप से, मैं यह कर सकता हूं:

$desired_object = Food::find(24);
$desired_object->color = 'Green';
$desired_object->save();

... लेकिन यह और भी अधिक सकल है , क्योंकि यह एक अतिरिक्त अनावश्यक क्वेरी करता है जब मेरे पास पहले से ही $foodsसंग्रह में वांछित वस्तु है ।

किसी भी मार्गदर्शन के लिए अग्रिम धन्यवाद।

संपादित करें:

स्पष्ट होने के लिए, आप किसी अन्य क्वेरी को प्रकाशित किए बिना एक प्रकाशित संग्रह पर कॉल कर सकते हैं->find() , लेकिन यह केवल एक प्राथमिक आईडी को स्वीकार करता है। उदाहरण के लिए:

$foods = Food::all();
$desired_food = $foods->find(21);  // Grab the food with an ID of 21

हालांकि, इस तरह के संग्रह से एक तत्व (ओं) को हथियाने के लिए अभी भी कोई साफ (गैर-लूपिंग, गैर-क्वेरी) तरीका नहीं है:

$foods = Food::all();
$green_foods = $foods->where('color', 'green'); // This won't work.  :(

जवाबों:


125

आप का उपयोग कर सकते हैं filter, जैसे:

$desired_object = $food->filter(function($item) {
    return $item->id == 24;
})->first();

filterएक भी वापस आ जाएगा Collection, लेकिन जब से आप जानते हैं कि केवल एक ही होगा, आप firstउस पर कॉल कर सकते हैं Collection

अब आपको फ़िल्टर की आवश्यकता नहीं है (या शायद कभी भी, मुझे नहीं पता कि यह लगभग 4 साल पुराना है)। आप बस उपयोग कर सकते हैं first:

$desired_object = $food->first(function($item) {
    return $item->id == 24;
});

7
धन्यवाद! मुझे लगता है कि मैं उसके साथ रह सकता हूं। अभी भी असामान्य रूप से इस तरह के 'एलोक्वेंट' ढाँचे के लिए मेरे विचार में क्रियात्मकता है। लेकिन यह अभी तक विकल्पों की तुलना में बहुत साफ है, इसलिए मैं इसे ले जाऊंगा।
लेंग

जैसा कि @squaretastic अन्य उत्तर में इंगित कर रहा है, आपके बंद होने के अंदर आप एक कार्य कर रहे हैं और तुलना नहीं कर रहे हैं (यानी आपको == और नहीं =)
ElementalStorm

24
वास्तव में यह आवश्यक नहीं है कि filter()->first()आप कॉल कर सकते हैंfirst(function(...))
लुकैजिटर

लारवेल कलेक्शन डॉक्यूमेंटेशन से। laravel.com/docs/5.5/collections#method-first collect([1, 2, 3, 4])->first(function ($value, $key) { return $value == 2; });
शेरो

2
आप एक ही काम कर सकते हैं, जहां फंक्शन हो। $desired_object = $food->where('id', 24)->first();
भाविन थुम्मर

111

लारवेल एक विधि प्रदान करता है जिसे keyByमॉडल में दी गई कुंजी द्वारा कुंजी सेट करने की अनुमति मिलती है।

$collection = $collection->keyBy('id');

संग्रह लौटाएगा, लेकिन कुंजी के मूल्यों के साथ id किसी भी मॉडल से विशेषता ।

तब आप कह सकते हैं:

$desired_food = $foods->get(21); // Grab the food with an ID of 21

और यह फिल्टर फ़ंक्शन का उपयोग करने की गड़बड़ी के बिना सही आइटम को पकड़ लेगा।


2
वास्तव में उपयोगी, विशेष रूप से प्रदर्शन के लिए, -> पहले () को कई बार (फोर्क में foreach ...) कहते हुए धीमा किया जा सकता है ताकि आप अपने संग्रह को "इंडेक्स" कर सकें जैसे: $exceptions->keyBy(function ($exception) { return $exception->category_id . ' ' . $exception->manufacturer_id;और ->get($category->id . ' ' . $manufacturer->id)बाद में उपयोग करें !
फ्रांस्वा ब्रेटन

क्या नए आइटम संग्रह में जोड़े जाने पर इस कुंजी का उपयोग जारी रहता है? या क्या मुझे हर बार एक नई वस्तु या सरणी को संग्रह पर धकेलने के लिए कीबी () का उपयोग करने की आवश्यकता है?
जेसन

सबसे अधिक संभावना है कि आपको इसे फिर से कॉल करना होगा क्योंकि keyByजो मुझे याद है, उससे नया संग्रह लौटाता है, हालांकि यह सुनिश्चित नहीं है, आप Illuminate/Support/Collectionइसे पता लगाने के लिए जांच कर सकते हैं। (काफी समय से लारवेल में काम न करना इसलिए कोई मुझे सही कर सकता है)।
मकसिम सीरजनिआक

यह मेरे लिए काम नहीं किया, यह एक और आइटम, अगले आइटम, अगर मैं टाइप (1) मिलता है यह आइटम नंबर जो आईडी पर 2 है वापस आ जाएगी।
जैकलिन पासोस

एक टेबल लोड करने में बैच लगा और एक दिन लग गया। इस घोल का इस्तेमाल किया और इसमें कुछ मिनट लगे।
जेड लिंच


7

चूंकि मुझे पूरे संग्रह को लूप करने की आवश्यकता नहीं है, इसलिए मुझे लगता है कि इस तरह से हेल्पर फ़ंक्शन करना बेहतर है

/**
 * Check if there is a item in a collection by given key and value
 * @param Illuminate\Support\Collection $collection collection in which search is to be made
 * @param string $key name of key to be checked
 * @param string $value value of key to be checkied
 * @return boolean|object false if not found, object if it is found
 */
function findInCollection(Illuminate\Support\Collection $collection, $key, $value) {
    foreach ($collection as $item) {
        if (isset($item->$key) && $item->$key == $value) {
            return $item;
        }
    }
    return FALSE;
}

7

का प्रयोग करें संग्रहण विधियों में बनाया शामिल और लगता है (सरणी कुंजी के बजाय) प्राथमिक आईडी के आधार पर खोज करेगा,। उदाहरण:

if ($model->collection->contains($primaryId)) {
    var_dump($model->collection->find($primaryId);
}

इसमें () वास्तव में सिर्फ कॉल लगता है () और अशक्त के लिए जाँच करता है, इसलिए आप इसे नीचे छोटा कर सकते हैं:

if ($myModel = $model->collection->find($primaryId)) {
    var_dump($myModel);
}

हम समझते हैं कि ढूंढना () एक प्राथमिक आईडी को स्वीकार करता है। हम जो चाहते हैं वह एक ऐसी विधि है जो किसी भी विशेषता को स्वीकार करती है, जैसे "रंग" या "आयु"। अब तक, कलली की विधि केवल एक ही है जो किसी भी विशेषता के लिए काम करती है।
लेंग

5

मुझे पता है कि यह प्रश्न मूल रूप से लारवेल 5.0 जारी होने से पहले पूछा गया था, लेकिन लारवेल 5.0 के रूप में, संग्रह where()इस उद्देश्य के लिए विधि का समर्थन करते हैं ।

लारवेल 5.0, 5.1 और 5.2 के लिए, वसीयत where()पर विधि Collectionकेवल एक समान तुलना करेगी। साथ ही, यह ===डिफ़ॉल्ट रूप से एक समान तुलना ( ) करता है। एक ढीली तुलना ( ==) करने के लिए, आप या तो falseतीसरे पैरामीटर के रूप में पास कर सकते हैं या whereLoose()विधि का उपयोग कर सकते हैं ।

लारवेल 5.3 के रूप में, क्वेरी बिल्डर के लिए विधि की where()तरह अधिक काम करने के लिए विधि का विस्तार किया गया था where(), जो एक ऑपरेटर को दूसरे पैरामीटर के रूप में स्वीकार करता है। क्वेरी बिल्डर की तरह, यदि कोई भी आपूर्ति नहीं की जाती है, तो ऑपरेटर बराबर की तुलना में डिफ़ॉल्ट होगा। डिफ़ॉल्ट तुलना को भी डिफ़ॉल्ट से ढीले करने के लिए डिफ़ॉल्ट से सख्त स्विच किया गया था। इसलिए, यदि आप एक सख्त तुलना चाहते हैं, तो आप उपयोग कर सकते हैं whereStrict(), या बस ===ऑपरेटर के रूप में उपयोग कर सकते हैं where()

इसलिए, Laravel 5.0 के रूप में, प्रश्न में अंतिम कोड उदाहरण बिल्कुल उसी तरह काम करेगा जैसे:

$foods = Food::all();
$green_foods = $foods->where('color', 'green'); // This will work.  :)

// This will only work in Laravel 5.3+
$cheap_foods = $foods->where('price', '<', 5);

// Assuming "quantity" is an integer...
// This will not match any records in 5.0, 5.1, 5.2 due to the default strict comparison.
// This will match records just fine in 5.3+ due to the default loose comparison.
$dozen_foods = $foods->where('quantity', '12');

3

मुझे यह बताना होगा कि कलली के उत्तर में एक छोटी लेकिन बिल्कुल क्रिटिकल त्रुटि है। साकार करने से पहले मैंने कई घंटों तक संघर्ष किया:

फ़ंक्शन के अंदर, आप जो वापस लौट रहे हैं वह एक तुलना है, और इस तरह कुछ इस तरह से अधिक सही होगा:

$desired_object = $food->filter(function($item) {
    return ($item->id **==** 24);
})->first();

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

1
**==**ऑपरेटर को कभी नहीं देखा , यह क्या करता है?
किराडोटी

@kiradotee मुझे लगता है कि ओपी केवल डबल बराबर तुलना ऑपरेटर ( == ) पर जोर देने का प्रयास कर रहा था । मूल उत्तर में केवल एक समान चिह्न का उपयोग किया गया था, इसलिए यह तुलना के बजाय एक असाइनमेंट कर रहा था। ओपी जोर देने की कोशिश कर रहा था कि दो समान संकेत होने चाहिए।
पेट्रीस


0

जैसा कि ऊपर सवाल जब आप क्लॉज का उपयोग कर रहे हैं तो आपको परिणाम प्राप्त करने के लिए प्राप्त या पहली विधि का उपयोग करने की आवश्यकता है।

/**
*Get all food
*
*/

$foods = Food::all();

/**
*Get green food 
*
*/

$green_foods = Food::where('color', 'green')->get();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.