LoginSignup
9
10

More than 3 years have passed since last update.

【Laravel】groupByを重ねて複数使う

Last updated at Posted at 2019-05-21

はじめに

Laravelのコレクションの便利なメソッドgroupBy

あれこれ触ったので、覚えたことを忘れないよう、練習問題にしてみました。

タイトルの、groupByを重ねて複数使う、最後の問3です。
すぐにやり方を知りたいという方はこちらへどうぞ。

問題

Order, OrderDetail, Book, Publisherモデルがあり、OrderDetailからリレーションのあるBook, Publisherまでを以下のように取得しました。

$order_details = OrderDetail::with('book.publisher')->get();

print_r(json_encode($order_details, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT))
$order_detailsをJSON化したもの
[
    {
        "id": 10001,
        "order_id": 1,
        "book_id": 111,
        "selling_price": 3000,
        "book": {
            "id": 111,
            "publisher_id": 11,
            "name": "自習Laravel",
            "list_price": 3500,
            "is_electronic_book": false,
            "publisher": {
                "id": 11,
                "name": "AA出版"
            }
        }
    },
    {
        "id": 10002,
        "order_id": 1,
        "book_id": 222,
        "selling_price": 2500,
        "book": {
            "id": 222,
            "publisher_id": 22,
            "name": "基礎から学ぶPHP",
            "list_price": 3000,
            "is_electronic_book": true,
            "publisher": {
                "id": 22,
                "name": "BB出版"
            }
        }
    },
    {
        "id": 10003,
        "order_id": 1,
        "book_id": 333,
        "selling_price": 3000,
        "book": {
            "id": 333,
            "publisher_id": 22,
            "name": "パーフェクトLaravel",
            "list_price": 3000,
            "is_electronic_book": false,
            "publisher": {
                "id": 22,
                "name": "BB出版"
            }
        }
    }
]

問1

publisher_idgroupByしてください。

問2

問1の結果では、グループ化された配列のキーはpublisher_idの値になります。(1122)

{
    "11": [
        {
            "id": 10001,
            "order_id": 1,
            "book_id": 111,
            "selling_price": 3000,
            "book": {
                "id": 111,
                "publisher_id": 11,
                "name": "自習Laravel",
                "list_price": 3500,
                "is_electronic_book": false,
                "publisher": {
                    "id": 11,
                    "name": "AA出版"
                }
            }
        }
    ],
    "22": [
        {
            "id": 10002,
            "order_id": 1,
            "book_id": 222,
//略

これを0から振り直してください。(JSON化した場合、以下のように出力されるようにしてください)

[
    [
        {
            "id": 10001,
            "order_id": 1,
            "book_id": 111,
            "selling_price": 3000,
            "book": {
                "id": 111,
                "publisher_id": 11,
                "name": "自習Laravel",
                "list_price": 3500,
                "is_electronic_book": false,
                "publisher": {
                    "id": 11,
                    "name": "AA出版"
                }
            }
        }
    ],
    [
        {
            "id": 10002,
            "order_id": 1,
            "book_id": 222,
//略

問3

まず、is_electronic_bookgroupByし、その上でそれぞれの要素に対して、publisher_idgroupByしてください。

補足

必要に応じてLaravel公式ドキュメントのgroupByほかを参照してください。
https://readouble.com/laravel/5.8/ja/collections.html#method-groupby

ここから先、解答になります。

...

...

...

解答

問1の解答

publisher_idgroupByしてください。

publisher_idは、bookをキーとする値の中に、さらにキーとして存在していました。

$order_detailsをJSON化したものの抜粋
        "book": {
            "id": 111,
            "publisher_id": 11,

こういった場合は、.で繋いで指定すればOKです。

問1の解答例
$answer1 = $order_details->groupBy('book.publisher_id');
問1の別解
$answer1 = $order_details->groupBy('book.publisher.id');

問2の解答

問1の結果では、グループ化された配列のキーはpublisher_idの値になります。(1122)
これを0から振り直してください。

キーの振り直しにはコレクションのメソッドであるvaluesが使えます。

valuesメソッドはキーをリセット後、連続した整数にした新しいコレクションを返します。

Laravel5.8 公式ドキュメント - values
https://readouble.com/laravel/5.8/ja/collections.html#method-values

問2の解答例
$answer2 = $order_details->groupBy('book.publisher_id')
    ->values();
問2の解答例の結果をJSON化したもの
[
    [
        {
            "id": 10001,
            "order_id": 1,
            "book_id": 111,
            "selling_price": 3000,
            "book": {
                "id": 111,
                "publisher_id": 11,
                "name": "自習Laravel",
                "list_price": 3500,
                "is_electronic_book": false,
                "publisher": {
                    "id": 11,
                    "name": "AA出版"
                }
            }
        }
    ],
    [
        {
            "id": 10002,
            "order_id": 1,
            "book_id": 222,
            "selling_price": 2500,
            "book": {
                "id": 222,
                "publisher_id": 22,
                "name": "基礎から学ぶPHP",
                "list_price": 3000,
                "is_electronic_book": true,
                "publisher": {
                    "id": 22,
                    "name": "BB出版"
                }
            }
        },
        {
            "id": 10003,
            "order_id": 1,
            "book_id": 333,
            "selling_price": 3000,
            "book": {
                "id": 333,
                "publisher_id": 22,
                "name": "パーフェクトLaravel",
                "list_price": 3000,
                "is_electronic_book": false,
                "publisher": {
                    "id": 22,
                    "name": "BB出版"
                }
            }
        }
    ]
]

問3の解答

groupByを重ねて複数使うには、同じくコレクションのメソッドであるtransformも利用することが考えられます。

問3の解答例
$answer3 = $order_details->groupBy('book.is_electronic_book')
    ->transform(function ($order_detail) {
        return $order_detail->groupBy('book.publisher_id')
            ->values(); // valuesは用途に応じてお好みで。詳細は問2参照。
        });

transformメソッドはコレクションを繰り返し処理し、コレクションの各アイテムに指定したコールバックを適用します。コレクション中のアイテムはコールバックから返される値に置き換わります。

Laravel5.8 公式ドキュメント - transform
https://readouble.com/laravel/5.8/ja/collections.html#method-transform

解答例ではis_electronic_bookgroupByした結果、2つの要素に分かれていますので、このtransformを使って各々の要素に対してさらにpublisher_idgroupByしています。

問3の解答例の結果をJSON化したもの
[
    [
        [
            {
                "id": 10001,
                "order_id": 1,
                "book_id": 111,
                "selling_price": 3000,
                "book": {
                    "id": 111,
                    "publisher_id": 11,
                    "name": "自習Laravel",
                    "list_price": 3500,
                    "is_electronic_book": false,
                    "publisher": {
                        "id": 11,
                        "name": "AA出版"
                    }
                }
            }
        ],
        [
            {
                "id": 10003,
                "order_id": 1,
                "book_id": 333,
                "selling_price": 3000,
                "book": {
                    "id": 333,
                    "publisher_id": 22,
                    "name": "パーフェクトLaravel",
                    "list_price": 3000,
                    "is_electronic_book": false,
                    "publisher": {
                        "id": 22,
                        "name": "BB出版"
                    }
                }
            }
        ]
    ],
    [
        [
            {
                "id": 10002,
                "order_id": 1,
                "book_id": 222,
                "selling_price": 2500,
                "book": {
                    "id": 222,
                    "publisher_id": 22,
                    "name": "基礎から学ぶPHP",
                    "list_price": 3000,
                    "is_electronic_book": true,
                    "publisher": {
                        "id": 22,
                        "name": "BB出版"
                    }
                }
            }
        ]
    ]
]

最後に

以上です。何問解けたでしょうか?

コレクションメソッドを使っていて、また何か気付きがあれば練習問題にしてみたいと思います:innocent:

参考

9
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10