mysql 按属性从集合中获取对象

5m1hhzi4  于 2022-12-17  发布在  Mysql
关注(0)|答案(9)|浏览(130)

在Laravel中,如果我执行查询:

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

...则$foodsFood模型对象的Illuminate Collection(本质上是模型数组)。
但是,此数组的键只是:

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

......因此,如果我想修改id为24的Food对象,我不能这样做:

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

...因为这只会改变数组中的第25个元素,而不是id为24的元素。

如何按ANY属性/列(例如但不限于id / color / age /等)从集合中获取单个(或多个)元素?

当然,我可以这样做:

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集合中已经有了所需对象时,它执行了一个额外的不必要的查询。
编辑:
需要说明的是,您 * 可以 * 在Illuminate Collection上调用->find(),而无需生成另一个查询,但它 * 仅 * 接受一个主ID。

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

但是,仍然没有一种干净的(非循环、非查询)方法可以通过属性从Collection中获取元素,如下所示:

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

2uluyalo1#

您可以使用filter,如下所示:

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

filter也将返回一个Collection,但是因为您知道只有一个,所以可以在那个Collection上调用first
你不再需要过滤器了(也许永远不需要了,我不知道这已经有4年的历史了),你可以直接使用first

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

mwyxok5s2#

Laravel提供了一个名为keyBy的方法,允许通过模型中的给定键设置键。
$collection = $collection->keyBy('id');
将返回集合,但键是任何模型的id属性的值。
然后你可以说:
$desired_food = $foods->get(21); // Grab the food with an ID of 21
并且它将抓取正确的项目,而不会使用过滤器函数的混乱。

njthzxwz

njthzxwz3#

从Laravel 5.5开始,您可以使用firstWhere()
在您的情况下:

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

kuarbcqp4#

使用内置的集合方法containfind,它们将按主ID(而不是数组键)搜索。

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

contains()实际上只是调用find()并检查是否为null,因此可以将其缩短为:

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

czfnxgou5#

因为我不需要循环整个集合,所以我认为最好使用这样的helper函数

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

ddrv8njm6#

我知道这个问题最初是在Laravel 5.0发布之前提出的,但是从Laravel 5.0开始,集合支持where()方法用于此目的。
对于Laravel 5.0、5.1和5.2,Collection上的where()方法将只执行等于比较。此外,默认情况下,它执行严格等于比较(===)。要执行松散比较(==),您可以将false作为第三个参数传递,或者使用whereLoose()方法。
从Laravel 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');
eqfvzcg8

eqfvzcg87#

可以采用用于查找值(http://betamode.de/2013/10/17/laravel-4-eloquent-check-if-there-is-a-model-with-certain-key-value-pair-in-a-collection/)的优雅解决方案:

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

kjthegm68#

正如上面的问题,当你使用where子句时,你也需要使用get Or first方法来得到结果。

/**
*Get all food
*
*/

$foods = Food::all();

/**
*Get green food 
*
*/

$green_foods = Food::where('color', 'green')->get();
x6492ojm

x6492ojm9#

如果您在Laravel中有一对多关系,您可以简单地编写以下内容。
(for例如,您有一个汽车制造商和汽车型号)

/** Initialize array */
            $data = [];

            /** Extract collection*/
            foreach (Model::all() as $model) {
                /** Initialize relation model array */
                $relationObjects = [];

                /** Iterate and make associative array */
                foreach ($model->relationObjects as $relObject) {
                    $relationObjects[] = $relObject->name; // name or whatever property you want
                }

                /** Push 'relationObjects' to coresponding 'modelName' key */
                $data[$model->name][] = $relationObjects;
            }

$data的格式为:

[   
    "Porsche": [
        [
            "Cayenne",
            "911 GT3"
        ]
    ],
    "Ford": [
        [
            "Mustang"
        ]
    ],
]

相关问题