Holen Sie sich das Objekt aus der Sammlung nach Attribut

Lesezeit: 6 Minuten

Benutzeravatar von Leng
Länge

Wenn ich in Laravel eine Abfrage durchführe:

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

…dann $foods ist ein Sammlung beleuchten von Food Modellobjekte. (Im Wesentlichen eine Reihe von Modellen.)

Die Schlüssel dieses Arrays sind jedoch einfach:

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

… also wenn ich ändern will, sagen wir, die Food Objekt mit einem id von 24 kann ich das nicht:

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

…weil dies nur das 25. Element im Array ändert, nicht das Element mit an id vom 24.

Wie erhalte ich ein einzelnes (oder mehrere) Element(e) aus einer Sammlung nach JEDEM Attribut/Spalte (z. B., aber nicht beschränkt auf, ID / Farbe / Alter / etc.)?

Natürlich kann ich das:

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

…aber das ist einfach ekelhaft.

Und das kann ich natürlich auch:

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

…aber das ist noch krasserweil es eine zusätzliche unnötige Abfrage durchführt, wenn ich das gewünschte Objekt bereits in der habe $foods Sammlung.

BEARBEITEN:

Um es klar zu sagen, Sie kann Anruf ->find() auf einer Illuminate-Sammlung, ohne eine weitere Abfrage zu erzeugen, aber es nur akzeptiert eine primäre ID. Zum Beispiel:

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

Es gibt jedoch immer noch keinen sauberen (ohne Schleifen, ohne Abfragen) Weg, um ein oder mehrere Elemente durch ein Attribut aus einer Sammlung zu erfassen, wie hier:

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

kalleys Benutzeravatar
Kalley

Sie können verwenden filterso:

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

filter wird auch a zurückgeben Collectionaber da Sie wissen, dass es nur einen geben wird, können Sie anrufen first auf diesem Collection.

Sie brauchen den Filter nicht mehr (oder vielleicht nie, ich weiß nicht, das ist fast 4 Jahre alt). Sie können einfach verwenden first:

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

  • Hey danke! Ich denke damit kann ich leben. Meiner Meinung nach immer noch ungewöhnlich ausführlich für einen normalerweise so ‘eloquenten’ Rahmen, haha. Aber es ist immer noch viel sauberer als die bisherigen Alternativen, also nehme ich es.

    – Länge

    5. Januar 2014 um 7:09 Uhr


  • Wie @squaretastic in der anderen Antwort hervorhebt, machen Sie in Ihrem Abschluss eine Zuordnung und keinen Vergleich (dh Sie sollten == und nicht = ).

    – Elementarsturm

    9. Juni 2014 um 12:57 Uhr

  • Eigentlich ist es nicht einmal notwendig anzurufen filter()->first() du kannst einfach anrufen first(function(...))

    – Lukasgeiter

    4. Februar 2015 um 20:10 Uhr

  • aus der Dokumentation der Laravel-Sammlung. laravel.com/docs/5.5/collections#method-first collect([1, 2, 3, 4])->first(function ($value, $key) { return $value == 2; });

    – Schiro

    12. Dezember 2017 um 15:25 Uhr

  • Sie können dasselbe mit der where-Funktion tun. $desired_object = $food->where('id', 24)->first();

    – Bhavin Thummar

    28. August 2018 um 11:02 Uhr

Benutzeravatar von Maksym
Maksym

Laravel bietet eine Methode namens keyBy die es erlaubt, Schlüssel nach gegebenem Schlüssel im Modell zu setzen.

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

gibt die Sammlung zurück, aber mit Schlüsseln, die die Werte von sind id Attribut von jedem Modell.

Dann kannst du sagen:

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

und es wird das richtige Element finden, ohne eine Filterfunktion verwenden zu müssen.

  • Wirklich nützlich, besonders für die Leistung, ->first() kann langsam sein, wenn es mehrmals aufgerufen wird (foreach in foreach …), sodass Sie Ihre Sammlung wie folgt “indizieren” können: $exceptions->keyBy(function ($exception) { return $exception->category_id . ' ' . $exception->manufacturer_id; und verwenden ->get($category->id . ' ' . $manufacturer->id) nach !

    – Francois Breton

    25. April 2016 um 16:32 Uhr


  • Wird dieser Schlüssel weiterhin verwendet, wenn der Sammlung neue Elemente hinzugefügt werden? Oder muss ich keyBy() jedes Mal verwenden, wenn ein neues Objekt oder Array in die Sammlung geschoben wird?

    – Jason

    22. September 2016 um 14:22 Uhr

  • Höchstwahrscheinlich müssen Sie es da noch einmal anrufen keyBy Gibt eine neue Sammlung zurück, soweit ich mich erinnere, aber nicht sicher, Sie können es überprüfen Illuminate/Support/Collection um es herauszufinden. (Arbeite seit einiger Zeit nicht mehr in Laravel, damit mich jemand korrigieren kann).

    – Maksym

    4. Dezember 2016 um 20:44 Uhr

  • Das hat bei mir nicht funktioniert, es hat ein anderes Element zurückgegeben, das nächste Element, wenn ich get(1) eingebe, wird das Element mit der Nummer 2 als ID zurückgegeben.

    – Jaqueline Passos

    21. Januar 2017 um 16:42 Uhr


  • Batch-Laden einer Tabelle und es dauerte einen Tag. Benutzte diese Lösung und es dauerte Minuten.

    – Jed Lynch

    27. April 2019 um 4:29 Uhr

Ab Laravel 5.5 können Sie verwenden zuerstWo()

In Ihrem Fall:

$green_foods = $foods->firstWhere('color', 'green');

  • Dies sollte die akzeptierte Antwort nach Laravel 5.5 sein

    – Bierwin

    13. März 2019 um 16:13 Uhr

Verwenden Sie die integrierten Erfassungsmethoden enthalten und finden, die nach primären IDs (anstelle von Array-Schlüsseln) sucht. Beispiel:

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

contains() ruft eigentlich nur find() auf und sucht nach null, also könnte man es verkürzen zu:

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

Da ich nicht die gesamte Sammlung durchlaufen muss, denke ich, dass es besser ist, eine Hilfsfunktion wie diese zu haben

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

Benutzeravatar von patricus
Patrikus

Ich weiß, dass diese Frage ursprünglich gestellt wurde, bevor Laravel 5.0 veröffentlicht wurde, aber ab Laravel 5.0 unterstützen Sammlungen die where() Methode zu diesem Zweck.

Für Laravel 5.0, 5.1 und 5.2 ist die where() Methode auf der Collection wird nur einen Gleichheitsvergleich durchführen. Außerdem führt es einen strikten Gleichheitsvergleich durch (===) standardmäßig. Um einen lockeren Vergleich zu machen (==), können Sie entweder bestehen false als dritten Parameter oder verwenden Sie die whereLoose() Methode.

Ab Laravel 5.3 ist die where() Methode wurde erweitert, um eher wie die zu funktionieren where() -Methode für den Abfragegenerator, der einen Operator als zweiten Parameter akzeptiert. Ebenso wie der Abfragegenerator verwendet der Operator standardmäßig einen Gleichheitsvergleich, wenn keiner angegeben wird. Der Standardvergleich wurde auch von standardmäßig streng auf standardmäßig lose umgestellt. Wenn Sie also einen strengen Vergleich wünschen, können Sie verwenden whereStrict()oder einfach verwenden === als Operator für where().

Daher funktioniert das letzte Codebeispiel in der Frage ab Laravel 5.0 genau wie beabsichtigt:

$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');

Benutzeravatar von softfrog
Weichfrosch

Elegante Lösung zum Finden eines Wertes (http://betamode.de/2013/10/17/laravel-4-eloquent-check-ob-es-ein-modell-mit-bestimmtem-schlüssel-wert-paar-in-einer-sammlung-gibt/) angepasst werden:

$desired_object_key = $food->array_search(24, $food->lists('id'));
if ($desired_object_key !== false) {
   $desired_object = $food[$desired_object_key];
}

1441080cookie-checkHolen Sie sich das Objekt aus der Sammlung nach Attribut

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy