3

Annotation Chartをデータベースからプール温度データを使用して作成したいと思います。Google Charts API DataTableの作成温度とIDのデータベースから

DROP TABLE IF EXISTS `temperatures`; 
DROP TABLE IF EXISTS `pools`; 

CREATE TABLE `pools` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, 
    `created_at` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 

CREATE TABLE `temperatures` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `pool_id` int(10) unsigned NOT NULL, 
    `temperature` double(8,1) NOT NULL, 
    `created_at` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `temperatures_pool_id_foreign` (`pool_id`), 
    CONSTRAINT `temperatures_pool_id_foreign` FOREIGN KEY (`pool_id`) REFERENCES `pools` (`id`) ON DELETE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=3173 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 

INSERT INTO `pools` (`id`, `name`, `created_at`) 
VALUES 
    (1,'Pool #1','2017-04-08 22:48:03'), 
    (2,'Pool #2','2017-04-08 22:48:03'), 
    (3,'Pool #3','2017-04-08 22:48:03'); 

INSERT INTO `temperatures` (`id`, `pool_id`, `temperature`, `created_at`) 
VALUES 
    (31,1,100.1,'2017-04-09 02:44:56'), 
    (32,2,104.2,'2017-04-09 02:44:56'), 
    (33,3,97.0,'2017-04-09 02:44:56'), 
    (34,1,100.1,'2017-04-09 03:00:04'), 
    (35,2,98.4,'2017-04-09 03:00:04'), 
    (36,3,96.6,'2017-04-09 03:00:04'), 
    (37,1,100.1,'2017-04-09 03:37:13'), 
    (38,2,101.8,'2017-04-09 03:37:13'), 
    (39,3,96.4,'2017-04-09 03:37:13'), 
    (40,1,100.1,'2017-04-09 04:00:04'), 
    (41,2,101.8,'2017-04-09 04:00:04'), 
    (42,3,96.5,'2017-04-09 04:00:04'), 
    (43,1,100.1,'2017-04-09 05:00:04'), 
    (44,2,101.8,'2017-04-09 05:00:04'); 

わかりましたので、基本的に、私が返すコントローラを作成している:あなたは、データベースの構造here on sqlfiddleまたはhere on rextesterを見てみることができますが、あなたのクリックを保存するために、ここで私が働いている構造です適切にアヤックスとgoogle.visualization.DataTable()で使用するためにJSONをフォーマットし、次のように:もちろん

var jsonData = $.ajax({ 
    url: "/data/pool-temperature-timeline", 
    dataType: "json", 
    async: false 
}).responseText; 

data = new google.visualization.DataTable(jsonData); 
chart.draw(data, options); 

、ドキュメントを見て、注釈・チャートは、このフォーマットをフォローする事を期待している:

var data = new google.visualization.DataTable(); 
data.addColumn('date', 'Date'); 
data.addColumn('number', 'Kepler-22b mission'); 
data.addColumn('string', 'Kepler title'); 
data.addColumn('string', 'Kepler text'); 
data.addColumn('number', 'Gliese 163 mission'); 
data.addColumn('string', 'Gliese title'); 
data.addColumn('string', 'Gliese text'); 
data.addRows([ 
    [new Date(2314, 2, 15), 12400, undefined, undefined, 
          10645, undefined, undefined], 
    [new Date(2314, 2, 16), 24045, 'Lalibertines', 'First encounter', 
          12374, undefined, undefined], 
    [new Date(2314, 2, 17), 35022, 'Lalibertines', 'They are very tall', 
          15766, 'Gallantors', 'First Encounter'], 
    [new Date(2314, 2, 18), 12284, 'Lalibertines', 'Attack on our crew!', 
          34334, 'Gallantors', 'Statement of shared principles'], 
    [new Date(2314, 2, 19), 8476, 'Lalibertines', 'Heavy casualties', 
          66467, 'Gallantors', 'Mysteries revealed'], 
    [new Date(2314, 2, 20), 0, 'Lalibertines', 'All crew lost', 
          79463, 'Gallantors', 'Omniscience achieved'] 
]); 

var chart = new google.visualization.AnnotationChart(document.getElementById('chart_div')); 

これはセットアップなので、今質問が来ます。 1)同じ日時のプール1,2、および3の温度データが常に存在するようにデータを整理する最良の方法は何ですか(データセットが所定のタイムスタンプでは完全ではないかと心配しています)。巧妙なクエリを使用してSQLレイヤーから整理する必要がありますか?または、foreachループを使用してコントローラーで整理しますか?私は巧妙なクエリは、コントローラのロジックとのforeachループの束を行うことを避けるために行くには良い方法だろう見ることができました

$dataTable->addRow(['created_at', 
    'temperature1', 'title1', 'text1', 
    'temperature2', 'title2', 'text2', 
    'temperature2', 'title2', 'text2', 
]); 

:これは私がのために努力しています目標です。データが列に組織された場合は多分、のような:

created_at, pool_1_temperature, pool_2_temperature, pool_3_temperature 
------------------------------------------------ 
2017-04-09 02:44:56, 100.1, 104.2, 97.0 
2017-04-09 03:00:04, 100.1, 98.4, 96.6 
2017-04-09 03:37:13, 100.1, 101.8, 96.4 

それから私はかなり簡単にそれを通過し、データテーブルを作成することができます。私はMySQLでこれをどうやって行うのか、それが良い考えであるかどうかはわかりません。

これまでのところ時間をとってくれてありがとうとありがとう、ありがとうございました。私は十分に明確であることを望む。

PS。私が今までに遭遇した最も近いものはMysql query to dynamically convert rows to columnsだと思います。私は...このもう少しで遊んするつもりだ

答えて

0

限り、日付、
はあなたが心配する必要はありませんが...あるx軸(最初の列)として

温度データはチャートのような

それをうまくすることができる必要があり、同じ日時

用プール1、2、および3の常にある、次のようなクエリを使用することができます。.. 。

select 
    created_at, 
    case when 
    pool_id = 1 
    then 
    temperature 
    else 
    null 
    end pool_1, 
    case when 
    pool_id = 2 
    then 
    temperature 
    else 
    null 
    end pool_2, 
    case when 
    pool_id = 3 
    then 
    temperature 
    else 
    null 
    end pool_3 
from 
    temperatures 

私はそう私はnullを返すことで

+0

これは一般的なルールとして、サーバーとクライアントの処理量が多いほど、ページの読み込み速度が速くなるため、できるだけ多くのロジックをSQLにプッシュすることをお勧めします。 。 – WhiteHat

+0

私はこれをとても感謝します。私は自分のチャートをどう扱うか考えていました。あなたはチャートが自分自身で細部のいくつかを動作させることができるということについて正しいものでした。ストアドプロシージャが必要なクレイジークエリでこれを処理するのではなく、ループとarray_pad()を使用してデータを整理しました。すぐに自分の質問に答えるつもりです...もう一度ありがとう!それは正しい軌道に乗った。 – dhildreth

0

を動作するかどうかわからないんだけど、SQL

を確認することができませんでした、
作業に提供するSQLのリンクのいずれかを取得することができませんでしたデータが動的であることを確認するために、将来別のプールが追加された場合には、array_pad()を使用してパッド付き配列に移動し、温度データセットをループして並べ替えることにしました。私もLavachartsを使って、Google DataTablesを扱いやすくしました。

$dataTable = \Lava::DataTable(); 
$dataTable->addDateTimeColumn('DateTime'); 

// Add data column for each pool 
$pools = \App\Pool::get(); 
foreach($pools as $pool) { 
    $p = "Pool $pool->id"; 
    $dataTable->addNumberColumn("$p Temp"); 

    // TODO: Create annotate fields for min and max temperatures 
    // For this, we'll need to do some clever padding using array_pad() 
    // and more clever index incrementing in the for() loop below. 
    // Perhaps it's best to calculate and prepare in the temperatures query? 
    //$dataTable->addStringColumn("$p Title"); 
    //$dataTable->addStringColumn("$p Text"); 
} 

// Gather all the temperature data we wish to display. A year ought to be enough. 
// At one hour updates, that makes for about 8,766 datapoints. 
$temperatures = \App\Temperature::where('created_at', '>=', \Carbon\Carbon::now()->subYear()) 
    ->orderBy('created_at', 'desc') 
    ->orderBy('pool_id', 'asc')->get(); 

// Grab all the timestamps and organize into an array 
$created_ats = \App\Temperature::groupBy('created_at')->pluck('created_at'); 

// Let's go through each datetime field and collect all temperatures recorded on that datetime. 
// Then, let's store those temperatures into the appropriate index of the data row. 
foreach($created_ats as $created_at) { 
    $dataRow = [$created_at]; // Start the array off by adding date to beginning 
    $dataRow = array_pad($dataRow, 1 + count($pools), null); // +1 to account for $created_at column 
    //$dataRow = array_pad($dataRow, 1 + (count($pools) * 3), null); // TODO: multiply by 3 for annotation fields 

    // Start going through each temperature recording and assign to proper spot in dataRow array 
    // If temperature is not found for the datetime, the array_pad() above already accounts for null 
    // in that index. Note, the created_at comparison only accounts for the hour, not seconds or minutes. 
    // TODO: Implement min and max temperature annotations. 
    //$maxTemperature = 0; 
    //$minTemperature = 999; 
    foreach($temperatures as $temperature) { 
     // TODO: Implement min and max temperature annotations. 
     //$maxTemperature = ($temperature->temperature >= $maxTemperature) ? $temperature->temperature : $maxTemperature; 
     //$minTemperature = ($temperature->temperature <= $minTemperature) ? $temperature->temperature : $minTemperature; 

     // Compare date and hour, then assign to appropriate index of the data row according to pool id. 
     // ie. Pool ID #1 needs to be placed in [1], Pool ID #2 in [2] and so forth. Remember, [0] is date. 
     if ($temperature->created_at->format('Y-m-d H') == $created_at->format('Y-m-d H')) { 
      for ($i = 1; $i <= count($pools); $i++) { 
       if($temperature->pool_id == $i) { 
        $dataRow[$i] = $temperature->temperature; 
       } 
      } 
     } 
    } 

    // We've gone through all temperatures for this created_at datetime. 
    // Add the resulting dataRow to the dataTable. 
    $dataTable->addRow($dataRow); 
} 

// What we're left with is a bunch of rows that look like this! 
// TODO: Add annoation fields for min and max temperatures. 
// $dataTable->addRow(['created_at', 
// 'temperature1', 
// 'temperature2', 
// 'temperature2' 
// ]); 
$jsonData = $dataTable->toJson(); 

// At this point, return $jsonData for use with google.visualization.DataTable(jsonData); 
// Or, cache it and then return it, or whatever. 

ビューでレンダリングする際に少し時間がかかるようだと、私は、データをキャッシュ推薦する(〜1.9s:だから、ここに私のコードは、(ノート、注釈フィールドを追加するために必要なより多くの仕事)です)。だから、おそらく最速の方法ではないかもしれませんが、それは私のためのトリックです。それ以上に掘り下げて、他の最適化を見つけることは興味深いでしょう。今のところ、私はそれに満足しています。

関連する問題