# 集合

## 不要使用 NULL 过滤集合

你可以在 Eloquent 中使用 `NULL` 过滤，但是你不能用 `NULL` 过滤 集合 - 你应该换成空字符串过滤，字段中已经没有 "null"。(意思是全字符串的形式的过滤不能使用 NULL，因为会被格式化为 \["field is null", "=", true])

```php
// This works
$messages = Message::where('read_at is null')->get();

// Won’t work - will return 0 messages
$messages = Message::all();
$unread_messages = $messages->where('read_at is null')->count();

// Will work
$unread_messages = $messages->where('read_at', '')->count();
```

## 使用自定义的回调函数对集合分组

如果你想对结果分组，且分组字段不对应数据库中的字段，你可以提供一个回调函数来返回自定义的分组字段。 例如，通过用户的注册日分组，代码如下：

```php
$users = User::all()->groupBy(function($item) {
    return $item->created_at->format('Y-m-d');
});
```

注意：这个方法是在 `Collection` 类上的，所以将会在数据库的返回结果上执行。(意思不会在数据库 sql 层面分组)

## 针对行的集合方法

你可以用 `->all(`) , `->get()` 方法查询数据，然后在这个返回的集合上执行各种集合方法，执行集合操作不会每次都查询数据库。

```php
$users = User::all();
echo 'Max ID: ' . $users->max('id');
echo 'Average age: ' . $users->avg('age');
echo 'Total budget: ' . $users->sum('budget');
```

## 对分页集合求和

如何对分页返回的结果集求和？使用相同的查询构建器，在分页查询之前执行求和操作

```php
// How to get sum of post_views with pagination?
$posts = Post::paginate(10);
// This will be only for page 1, not ALL posts
$sum = $posts->sum('post_views');

// Do this with Query Builder
$query = Post::query();
// Calculate sum
$sum = $query->sum('post_views');
// And then do the pagination from the same query
$posts = $query->paginate(10);
```

## 分页组件中的唯一标识

我们可以在分页组件中像序列号那样使用每趟循环中的索引 `index` ，作为分页组件的唯一标识。

```php
   ...
   <th>Serial</th>
    ...
    @foreach ($products as $product)
    <tr>
        <td>{{ $loop->index + $product->firstItem() }}</td>
        ...
    @endforeach
```

这可以解决下一页（?page=2&...）索引的计数问题。

## 高阶集合方法

集合具有更高阶的可以链式调用的方法，例如 `groupBy()` `map()` 等，给你流畅的语法体验。下面的例子计算了一个需求单中每组产品的价格。

```php
$offer = [
        'name'  => 'offer1',
        'lines' => [
            ['group' => 1, 'price' => 10],
            ['group' => 1, 'price' => 20],
            ['group' => 2, 'price' => 30],
            ['group' => 2, 'price' => 40],
            ['group' => 3, 'price' => 50],
            ['group' => 3, 'price' => 60]
        ]
];
                
$totalPerGroup = collect($offer->lines)->groupBy('group')->map(fn($group) => $group->sum('price')); 
```

## 高阶集合排序

集合还支持“高阶排序”，这是对集合执行常见操作的捷径。

此示例计算报价中每组产品的价格。

```php
$offer = [
        'name'  => 'offer1',
        'lines' => [
            ['group' => 1, 'price' => 10],
            ['group' => 1, 'price' => 20],
            ['group' => 2, 'price' => 30],
            ['group' => 2, 'price' => 40],
            ['group' => 3, 'price' => 50],
            ['group' => 3, 'price' => 60]
        ]
];
                
$totalPerGroup = collect($offer['lines'])->groupBy->group->map->sum('price');
```

## 获取一个键，如果不存在则插入一个值，并返回该值

在 Laravel 8.81 中添加了 `getOrPut` 方法到集合，简化了你想获得一个键，如果它不存在，插入一个值并返回值的使用情况。

```php
$key = 'name';
// Still valid
if ($this->collection->has($key) === false) {
    $this->collection->put($key, ...);
}

return $this->collection->get($key);

// Using the `getOrPut()` method with closure
return $this->collection->getOrPut($key, fn() => ...);

// Or pass a fixed value
return $this->collection->getOrPut($key, $value='teacoders');
```

由 [@Teacoders](https://twitter.com/Teacoders/status/1488338815592718336) 提供


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tips.laradoc.cn/collections.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
