質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.75%

  • PHP

    19178questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • MySQL

    5513questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • AWS(Amazon Web Services)

    1834questions

    Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

  • Laravel 5

    1692questions

    Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

  • Laravel

    603questions

    LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

【laravel・RDS】DBに保存されている配列がnullになり取得できない(取得するjson配列が途中で切れる)

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 623

youthK

score 64

わからないこと

配列でIDを取得してそれをもとに一覧ページを表示しています。
しかし、該当箇所でnullとなり、dd()で確認したところ、配列が途中までしか表示されておりませんでした。
すべての表示結果でそうなるわけではなく、一定数以上の件数でのみそうなっており、データ量が影響しているのではと考えております。
どうしてそうなるのかがわかっておらず、したがってどう対処すればよいのかわかっておりません。
ご教授いただければ幸いです。

※変数に格納してあるデータが1Mちょうどで収まっているのを確認しました。つまり1Mを超えたデータについては切られている状況になります。
そのため、json配列の「 ] 」も切られているので、nullが取得されていると考えています。

コード

protected $casts = array(
    'result' => 'array',
    'query' => 'array',
);
$data = Search::select('result', 'query')->where('id', 5)->first();
$all = $data ? $data['result'] : [];


上記の「$data['result']」にddをかけるとnullが取得されます。
※Searchはsearchesというテーブルを指します。
そのうちの「result」カラムが非常に肥大している状況です。
通常ですと、「result:[1, 2, 3, ..., 555555]」のように表示されるのですが、「 result:[1, 2, 3, ..., 555554, 」と表示されています。

テーブル構造

Name: searches
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 83424
Avg_row_length: 37212
Data_length: 3104407552
Max_data_length: 0
Index_length: 0
Data_free: 7340032
Auto_increment: 89328
Create_time: 2017-07-11 23:28:01
Update_time: 2017-10-04 06:19:23
Check_time: NULL
Collation: utf8_unicode_ci
Checksum: NULL
Create_options:
Comment:

よろしくお願いいたします。

追加事項

モデル

protected $table = 'searches';
protected $casts = array(
    'id' => 'integer',
    'result' => 'array',
    'query' => 'array',
);

テーブル構造

`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `result` longtext COLLATE utf8_unicode_ci NOT NULL,
  `query` longtext COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=89390 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_c

queryの中身

array:3 [▼
  "pha" => array:18 [▶]
  "q" => ""
  "pri" => []
]

ddの結果

Search {#987 ▼
  #table: "searches"
  #casts: array:3 [▶]
  #connection: null
  #primaryKey: "id"
  #perPage: 15
  +incrementing: true
  +timestamps: true
  #attributes: array:2 [▼
    "result" => "[142264,142265,142266,142263,142262,142261,142260,...]
 "query" => "{"phase":[1,2,3,5,6,8,12,32,10,11,28,29,27,26,25,31,24,0],"q":"","privacy":[]}"
]

追記

$search = (int)request()->input('search');
        if ($search) {
            $data = Search::select('result', 'query')->where('id', $search)->first();
            dd(strlen($data->getAttributeFromArray('result')));
            $all = $data ? $data['result'] : [];
            $q   = isset($data['query']['q']) ? $data['query']['q'] : '';
            $phaseIds[0] = isset($data['query']['phase']) ? $data['query']['phase'] : [];
            $privacy = isset($data['query']['privacy']) ? $data['query']['privacy'] : [];
        } else {
            $phaseIds[0] = array_unique(array_map('intval', (array)request()->input('phase')));
            if ($phaseIds[0]) {
            } elseif (request()->ajax()) {
                unset($phaseIds[0]);
                unset($phaseIds[1]);
                $phaseIds = array_values($phaseIds);
            } else {
                $phaseIds[0] = array_values(array_diff(last($phaseIds),(array)Option::getArray(Option::JPHASE_FINISH)));
            }
            // 検索フォームでの検索値の取得
            $q = (string)request()->input('q');
            // 各種ポータルサイトへの公開/非公開設定の取得
            $privacy = array_unique((array)request()->input('privacy'));
            // 全案件のidを取得
            $all = self::commitSearch($q, $phaseIds[0], $privacy);
            // インスタンスの生成
            $search = new Search();
            $search['result'] = $all;
            $search['query']  = ['phase'=>$phaseIds[0],'q'=>$q,'privacy'=>$privacy];
            $search->save();
            $search = $search['id'];
        }
public static function commitSearch($q, $phaseIds, $privacy, $ids = NULL) {
        $fulltext = Fulltext::where('type', 'job')->orderBy('time','DESC');
        if ($ids) $fulltext->whereIn('main_id', $ids);
        if ($phaseIds) $fulltext->whereIn('phase_id', $phaseIds);
        if ($q !== '') $fulltext->whereIndex($q);
        if (!$privacy || count($privacy) === 3) {
            return array_map('intval', $fulltext->lists('main_id')->toArray());
        } elseif (!($ids = array_map('intval', Job::whereIn('privacy', $privacy)->lists('id')->toArray()))) {
            return [];
        } elseif (count($ids) <= 10000) {
            $fulltext->whereIn('main_id', $ids);
            return array_map('intval', $fulltext->lists('main_id')->toArray());
        } else {
            return array_values(array_intersect(array_map('intval', $fulltext->lists('main_id')->toArray()), $ids));
        }
    }

追記②

「strlen(getAttribute['result'])」:1041645

「substr(getAttribute['result'], -10)」:"7392,7372,"

「LENGTH(result)」:1053784

「RIGHT(result, 10)」:1576,3449]

現状報告

調べたところ、1MBを境目にエラーが発生しているようです。
そのため、phpとmysqlの設定をあらっている現状になります。

バージョン

php7
laravel5.1
データベース:RDS(mysql5.7)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • masaya_ohashi

    2017/10/05 15:09

    すみません、よく調べてみたところ、getAttributeFromArrayはprotectedなメソッドであったため、getAttributes()['result']で代用してください。

    キャンセル

  • youthK

    2017/10/05 15:14

    DBでは、Length:1051656、Cnt:157323.0000、PHPでは1048576と表示されました。ご推測の通り件数がずれていると思われます

    キャンセル

  • masaya_ohashi

    2017/10/05 15:19

    私の回答を修正したので、修正後のコードで再度試してみてください。

    キャンセル

回答 3

checkベストアンサー

+6

これまで切り分け頂いている結果から、おそらく下記が該当するのではないかと思います。

LaravelとMySQLで1048576の罠

PDOでMySQLに接続している場合、PDO::MYSQL_ATTR_MAX_BUFFER_SIZEのデフォルト値が1MiBとなっており、それ以上のサイズの列を取得することができないという事象です。

対処としては、上記サイトにもあるように、app/config/database.phpの options で十分大きなサイズのバッファを確保するように指定することで対応できるのではないかと思います。
上記サイトでは16MBに設定しているようです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/06 02:30

    夜分遅くにありがとうございます!!
    上記の設定にて無事表示させることができました。
    ありがとうございました

    キャンセル

  • 2017/10/06 09:04

    すごい!モヤモヤが取れました!

    キャンセル

+4

Laravelの場合、クエリビルダーやEloquentクラスで結果を取得した場合、通常は配列ではなくオブジェクトになるのではないかと思います。

参考:
https://readouble.com/laravel/5.1/ja/queries.html
の「テーブルから1カラム/1レコード取得」項

そのため、
$data['result']

$data->result

に変更してはいかがでしょう?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/05 14:05

    ご回答ありがとうございます。
    json_decodeで配列にするなども試みましたが、それでもやはりnullのままでした。

    キャンセル

  • 2017/10/05 14:13

    「他の関数を使ってオブジェクトを配列にする」ではなく、「$data->result」という書き方で、値を取得できるかどうかは試されましたか?(LaravelのEloquentクラスは単純なオブジェクトではなく、マジックメソッド等がいろいろ仕事をしているので、単にobject→arrayに変換するだけですとうまくいかないかもしれません)

    もしまだでしたら、一度そちらをお試しいただきたいです。

    キャンセル

  • 2017/10/05 14:16

    アドバイスを頂いた通り、
    「$all = $data ? $data['result'] : [];」

    「$all = $data ? $data->result : [];」
    に変更してみましたが、結果は同じでした。

    キャンセル

  • 2017/10/05 14:18

    検索結果で表示される件数によってnullが出たり、配列が出たりと変わってしまっています。
    15万件以上ですとnullに、それ以下ですと配列が出力される状況です。

    キャンセル

  • 2017/10/05 14:34

    ちょっと待ってください、質問でやり取りしていたresultの長さとカンマのカウントのときLENGTHは11626と言ってましたが、15万件のデータでresultが11626ってありえなくないですか?

    キャンセル

  • 2017/10/05 14:35

    カンマの数も15万に遠く及ばず2389です。これは保存処理自体が誤っているのではないでしょうか?

    キャンセル

  • 2017/10/05 14:39

    +---------+-------------+
    | LEN | CNT |
    +---------+-------------+
    | 1052645 | 157470.0000 |
    +---------+-------------+
    失礼いたしました。
    その際お渡ししたデータが誤っていました。
    データについては上記でお願いします

    キャンセル

  • 2017/10/05 14:42

    ご確認ありがとうございます。

    > 15万件以上ですとnullに、それ以下ですと配列が出力される状況です。

    ということは、取得方法には問題なさそうですね。

    データ量が多い時特有の問題のようですので、お役に立てない気がしてきました(申し訳ない限りです……)。

    どうか解決にいたりますように。

    キャンセル

  • 2017/10/06 02:31

    無事解決に至ることができました
    ありがとうございました!

    キャンセル

  • 2017/10/06 12:04

    よかったです。お二方とも、お疲れ様でした!

    キャンセル

+4

らちがあかないので、デコードでなにが起きたのかエラーを検知するコードを作りました。直接的な問題の解決ではないですが、手がかりになるかと思います。

$data = Search::select('result', 'query')->where('id', 5)->first();

$json_array = json_decode($data->getAttributes()['result']));

// この処理を追加
switch (json_last_error()) {
        case JSON_ERROR_NONE: dd('JSON_ERROR_NONE'); break;
        case JSON_ERROR_DEPTH: dd('JSON_ERROR_DEPTH'); break;
        case JSON_ERROR_STATE_MISMATCH: dd('JSON_ERROR_STATE_MISMATCH'); break;
        case JSON_ERROR_CTRL_CHAR: dd('JSON_ERROR_CTRL_CHAR'); break;
        case JSON_ERROR_SYNTAX: dd('JSON_ERROR_SYNTAX'); break;
        case JSON_ERROR_UTF8: dd('JSON_ERROR_UTF8'); break;
        case JSON_ERROR_RECURSION: dd('JSON_ERROR_RECURSION'); break;
        case JSON_ERROR_INF_OR_NAN: dd('JSON_ERROR_INF_OR_NAN'); break;
        case JSON_ERROR_UNSUPPORTED_TYPE: dd('JSON_ERROR_UNSUPPORTED_TYPE'); break;
        case JSON_ERROR_INVALID_PROPERTY_NAME: dd('JSON_ERROR_INVALID_PROPERTY_NAME'); break;
        case JSON_ERROR_UTF16: dd('JSON_ERROR_UTF16'); break;
    }

 追記

不整合の原因が、モデルへの変換過程で起きるのか、DBから値を取得する際に起こるのかを判断するため、このコードを試してください。

// Modelへの代入を行わず、レコードをstdClassの配列形式で得られる
$data = \DB::select(\DB::raw("SELECT * FROM searches WHERE id = :id"), ['id' => $id]);
dd(strlen($data[0]->result));
// もし文字列長が正しければ以下も実験
$a = json_decode($data[0]->result, true);
dd($a);

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/05 14:25

    何度も誠にありがとうございます。
    上記早速試みましたが、JSON_ERROR_NONEが出力されました。

    キャンセル

  • 2017/10/05 15:21

    ありがとうございます。
    今度は「JSON_ERROR_SYNTAX」と表示されました

    キャンセル

  • 2017/10/05 15:25

    DBに保存された値がJSONとして正しくない、ということになります。やはり保存の処理の辺りで何か問題が起きているようですね。

    キャンセル

  • 2017/10/05 15:25

    あ、違うな、DBから読み込んでモデルに入れられた値がJSON形式から崩れている、が正しいかもしれないです。

    キャンセル

  • 2017/10/05 15:28

    DBのデータの出力するところで崩れが起こってしまっているのですね・・・
    ということは、それは配列を区切っているカンマがおかしなことになっているということでしょうか?

    キャンセル

  • 2017/10/05 15:33

    追記しました。追記したコードも試して長さを比べてください。

    キャンセル

  • 2017/10/05 15:36

    ありがとうございます。
    ただ、
    FatalThrowableError in JobController.php line 192:
    Cannot use object of type stdClass as array
    のエラーが起こってしまいます。

    キャンセル

  • 2017/10/05 15:41

    すみません、自分でstdClass形式で得ると書いておきながらobject形式なアクセスをしてました。コードを修正しました。

    キャンセル

  • 2017/10/05 15:43

    $data = \DB::select(\DB::raw("SELECT * FROM searches WHERE id = :id"), ['id' => $id]);
    dd(strlen($data[0]->result));
    を試みましたが、文字列長は変わらずずれたままでした

    キャンセル

  • 2017/10/05 15:47

    確認なのですが、正しく読み込めるデータはずれないですか?

    キャンセル

  • 2017/10/05 15:48

    正しく読み込めるデータというのはDBのデータでしょうか?

    キャンセル

  • 2017/10/05 15:54

    正しくresultにアクセス可能なデータ(nullにならない)の、PHP上でのstrlen($data->getAttributes()['result'])とDB上でのLENGTH(result)が同じかどうかです。

    キャンセル

  • 2017/10/05 15:57

    はい、ズレなく一致していました。

    キャンセル

  • 2017/10/05 16:06

    ということは「DBからの読み込み時に、PHP側で何らかの理由で文字列が欠け落ちてしまう」ことが原因でほぼ間違いないようですね。その方面から探ってみましょう。

    キャンセル

  • 2017/10/05 16:10

    かしこまりました
    ddした際に、var_dump同様すべての文字列が出力されないのは理解していますが、「...」もなくぶっつりと配列が切れているのは、文字列を完全に取得できていないこととは無関係でしょうか?

    キャンセル

  • 2017/10/05 16:17

    そういえばまだ「PHP側で受け取った文字列の末尾」がどうなっているか確認していませんでしたね。次はdd(substr($data->getAttributes()['result'], -10))) を試して末尾10文字程度がどうなっているか見てみましょう。

    キャンセル

  • 2017/10/05 16:20

    "624,61669]"
    問題なくありました。

    キャンセル

  • 2017/10/05 16:21

    失礼いたしました!

    "7392,7372,"

    ありませんでした

    キャンセル

  • 2017/10/05 16:22

    これは有力な情報ですね。そのデータはDB上の末尾は正しく]で終わっているものですよね?

    キャンセル

  • 2017/10/05 16:23

    はい、仰る通り正しくは「 ] 」で終わるべきデータです。

    キャンセル

  • 2017/10/05 16:24

    いや、「べき」でなくちゃんと確認してください。DBでRIGHTを使って同一レコードの末尾が正しく]で閉じられているか確認してください。

    キャンセル

  • 2017/10/05 16:29

    失礼いたしました。

    1576,3449]

    ↑は同一IDによる同一レコードになります。

    キャンセル

  • 2017/10/05 16:52

    確認したところ、PHP側でのjson出力では、どうも文字列が途中までしか出力されていないようです。

    キャンセル

  • 2017/10/05 17:11

    私の環境で1から50万の配列を作って同様の取得をしてみたのですが、普通に配列が取得出来てしまいました…

    キャンセル

  • 2017/10/05 17:16

    php側の設定の問題でしょうか・・・

    キャンセル

  • 2017/10/05 17:22

    その可能性はあります。そろそろ私からの検証も限界に近いですね…念のため質問文に「エラーが起きるデータ」で取った「strlen(getAttribute['result'])」「substr(getAttribute['result'], -10)」「LENGTH(result)」「RIGHT(result, 10)」それぞれの値を表にしてまとめておいてもらえますか?
    それとLaravel、phpのバージョンも併記してみると他の人が何かピンとくるかもしれません。

    キャンセル

  • 2017/10/05 18:01

    かしこまりました
    正面から答えてくださり、ありがとうございました。

    キャンセル

  • 2017/10/05 18:03

    惜しい、LENGTH(result)が抜けています。

    キャンセル

  • 2017/10/05 18:10

    ご指摘ありがとうございます。
    修正しました

    キャンセル

  • 2017/10/06 02:31

    無事回答を頂きまして解決することができました。
    ご助力いただきましてありがとうございました

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.75%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • PHP

    19178questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • MySQL

    5513questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • AWS(Amazon Web Services)

    1834questions

    Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

  • Laravel 5

    1692questions

    Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

  • Laravel

    603questions

    LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

  • トップ
  • PHPに関する質問
  • 【laravel・RDS】DBに保存されている配列がnullになり取得できない(取得するjson配列が途中で切れる)