I'm trying to set up some simple Amcharts graphs for a company intranet webpage. Over the last two weeks I have created HTML/JS and produced a nice graphic using Amcharts (data hard-coded in the HTML for demo purposes). I also installed XAMPP and created a MySQL database, populated with tables and some data that gets imported from csv files.
So far, everything is working fine - I can display nice graphics and I can collect the data for supplying data to the graphs. However, I have been approaching this problem from the 2 ends (getting the source data into a database AND presenting the data in a graph on a webpage). Now I need to join these 2 ends, so I can feed Amcharts with data from MySQL.
I know I need to use PHP to get the data from MySQL and put this into an array that can be used by Amcharts but my PHP knowledge is very basic and I'm struggling with the code.
What I have is PHP code which successfully connects to MySQL and extracts data to display in a browser - that works. I just don't know how to get that data into a multi-dimensional array in the format that Amcharts needs for plotting its graph.
It would be really great if you guys could give me some help here and fill in the missing pieces. I have some pseudo code for the logic of creating the array as the basis for the 'real' php code.
This is the pseudo code for populating the array:
;charset=UTF-8', '', '', array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$stmt = $db->query("SELECT * FROM <mytable> WHERE <mycondition>");
$prevweek = "9999";
$headrowdone = 0;
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($prevweek < $row['WeekNumber']) {
// New week so write out Category X Label ('Week') with the week number of the following data rows
chartData.push($DataRow);
$headrowdone = 0;
}
if (!$headrowdone) {
$DataRow = "Week: "+$row['WeekNumber'];
$headrowdone = 1;
}
// Write out the X-Axis Category value and the Y-Axis value
$DataRow = $DataRow+$row['XAxisCategory']+": "+$row['YAxisCategory'];
$prevweek = $row['WeekNumber'];
}
chartData.push($DataRow); ?>
The SQL table looks like:
CREATE TABLE ( WeekNumber varchar(4), XAxisCategory
varchar(50), YAxisValue integer );
and has data like: '1301','A',10 '1301','B',20 '1301','C',24
'1302','A',11 '1302','B',22 '1302','C',27 '1303','A',14 '1303','B',23
'1303','C',28 ...etc
The data array for amcharts needs to look like:
var chartData = [{ Week: "1301",
A: 10,
B: 20,
C: 24
}, {
Week: "1302",
A: 11,
B: 22,
C: 27
}, {
Week: "1303",
A: 14,
B: 23,
C: 28
....etc
}];
// This is spoofing your fetch via pdo
$rows [] = array('WeekNumber'=>1301, 'A'=>10);
$rows [] = array('WeekNumber'=>1301, 'B'=>20);
$rows [] = array('WeekNumber'=>1301, 'C'=>25);
$rows [] = array('WeekNumber'=>1302, 'A'=>12);
$rows [] = array('WeekNumber'=>1302, 'B'=>22);
$rows [] = array('WeekNumber'=>1302, 'C'=>27);
//var_dump($rows);
// set up some vars
$lastweek = '';
$ctr = 0;
$data = array();
// loop thru the vars, build another array
foreach( $rows as $row){
if($row['WeekNumber'] !== $lastweek){
$ctr++;
$data[$ctr] = array('Week'=>$row['WeekNumber']);
$lastweek= $row['WeekNumber'];
}
// this could be nicer, but for now will do
if( isset($row['A']) ) $data[$ctr]['A'] = $row['A'];
if( isset($row['B']) ) $data[$ctr]['B'] = $row['B'];
if( isset($row['C']) ) $data[$ctr]['C'] = $row['C'];
}
var_dump($data);
Then use json_encode() to get into the format you want.
This answer is a bit kludgy, but at least gets away from building strings to make json.
Related
I know how to get a mysql-row and convert it to json:
$row = mysqli_fetch_assoc(mysqli_query($db, "SELECT * FROM table WHERE id=1"));
echo json_encode($row); // it's an ajax-call
but:
the db-row has different types like int, float, string.
by converting it using json_encode() all results are strings.
Is there a better way to correct the types than this:
$row['floatvalue1'] = 0+$row['floatvalue1'];
$row['floatvalue2'] = 0+$row['floatvalue2'];
$row['intvalue1'] = 0+$row['intvalue1'];
I would like to loop through the keys and add 0 because:
first coding rule: DRY - dont repeat yourself
but i can't because:
row has also other types than numbers (string, date)
there are many columns
design is in dev, so columns-names often changes
Thanks in advance and excuse my bad english :-)
EDIT (to answer the comment-question from Casimir et Hippolyte):
I call this php-code using ajax to get dynamically sql-values. in my javascript-code i use the results like this:
result['intvalue1'] += 100;
lets say the json-result of intval1 is 50, the calculated result is:
"50100", not 150
The code below is just a proof of concept. It needs encapsulation in a function/method and some polishing before using it in production (f.e. call mysqli_fetch_field() in a loop and store the objects it returns before processing any row, not once for every row).
It uses the function mysqli_fetch_field() to get information about each column of the result set and converts to numbers those columns that have numeric types. The values of MYSQLI_TYPE_* constants can be found in the documentation page of Mysqli predefined constants.
// Get the data
$result = mysqli_query($db, "SELECT * FROM table WHERE id=1");
$row = mysqli_fetch_assoc($result);
// Fix the types
$fixed = array();
foreach ($row as $key => $value) {
$info = mysqli_fetch_field($result);
if (in_array($info->type, array(
MYSQLI_TYPE_TINY, MYSQLI_TYPE_SHORT, MYSQLI_TYPE_INT24,
MYSQLI_TYPE_LONG, MYSQLI_TYPE_LONGLONG,
MYSQLI_TYPE_DECIMAL,
MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE
))) {
$fixed[$key] = 0 + $value;
} else {
$fixed[$key] = $value;
}
}
// Compare the results
echo('all strings: '.json_encode($row)."\n");
echo('fixed types: '.json_encode($fixed)."\n");
something like
$row['floatvalue1'] = reset( sscanf ( $row['floatvalue1'] , "%f" ));
$row['floatvalue2'] = reset( sscanf ( $row['floatvalue2'] , "%f" ));
$row['intvalue1'] = reset( sscanf ( $row['intvalue1'] , "%d" ));
json_encode($row);
If you're simply trying to make sure that your values are operable with respect to their type, you need to first cast their type correctly.
Unless you need them server-side, I would just pass-on the json directly to the front-end and do the work there.
In Javascript, you could make an attempt at casting the numbers like so:
function tryNumber(string){
return !isNaN( parseInt(string) ) ? parseInt(string) : string;
}
function tryDate(string){
return !isNaN( new Date(string).getTime() ) ? new Date(string) : string;
}
tryNumber('foo'); // "hello"
tryNumber('24'); // 24
tryDate('bar'); // "bar"
tryDate('December 17, 1995'); // "Sun Dec 17 1995 00:00:00 GMT+0000 (GMT)"
These two lines attempt to cast the values as a Date/Number. If they can't be cast, they will remain String's.
A MySQLi OO version based on #axiac's answer, that produces a JSON array ($jsnAll) containing all records. In this code snippet, the method FixSQLType is called to fix a row. Note, it should be wrapped in a try{}catch{} block and "objMySQLi" has already been instantiated:
$lcAllRows = array();
// Make an SQL SELECT statement
$SQL = "SELECT * FROM $lcName WHERE $lcWhere";
// Run the query
$this->sqlResult = $this->objMySQLi->query($SQL);
// Fetch the result
while( $row = $this->sqlResult->fetch_assoc()){
$lcCount = count($lcAllRows) ;
// Call to fix, row
$fixedRow = $this->FixSQLType($row);
$lcAllRows[$lcCount]= $fixedRow;
}
$jsnAll = json_encode($lcAllRows);
The FixSQLType method. This is almost identical to #axiac's answer, except for the call to $this->sqlResult->fetch_field_direct($i). "fetch_field" seemed to get itself lost, using "fetch_field_direct" overcame that problem.
private function FixSQLType($pRow){
// FROM https://stackoverflow.com/a/28261996/7571029
// Fix the types
$fixed = array();
$i = 0;
foreach ($pRow as $key => $value) {
$info = $this->sqlResult->fetch_field_direct($i);
$i++;
if (in_array($info->type, array(
MYSQLI_TYPE_TINY, MYSQLI_TYPE_SHORT, MYSQLI_TYPE_INT24,
MYSQLI_TYPE_LONG, MYSQLI_TYPE_LONGLONG,
MYSQLI_TYPE_DECIMAL,
MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE
))) {
$fixed[$key] = 0 + $value;
} else {
$fixed[$key] = $value;
}
}
return $fixed;
}
I am trying to Plot a Graph with FLOT but I cant get my head around how to get make it Dynamic with multiple series.
I am trying to get Race Data , Eg Laps and Time as the Graph x and y, but also trying to get the Race ID as a new series line for each Rider.
I have tried it at a Loop for each RaceID, and I have tried it as a multidimensional array, But I cant get my head around how to get it formatted to how FLOT wants it.
I can get it to work with 1 Rider:
$GetLapData = mysql_Query("SELECT LapData.*, u.RaceID
FROM `LapData`
left join User as u on LapData.TagID = u.TagID
Where LapData.EventID = '$EventID'
and LapData.RaceNameID = '$RaceNameID'
and LapData.TagID = '$RacingNumber'
ORDER BY `LapData`.`LapNumber` ASC");
while ($row = mysql_fetch_assoc($GetLapData))
{
$dataset1[] = array($row['LapNumber'],$row['LapTimeinSeconds']);
}
and then plot the single Data Set
$(function() {
var d1 = <?php echo json_encode($dataset1) ?>;
$.plot("#placeholder", [ d1 ]);
});
Any Ideas on making it all riders for the Race would be really helpful.
This is a tough question to answer without seeing your database scheme, but I'll give it a shot.
First, let's modify your SQL statement. I'm guessing that this part and LapData.TagID = '$RacingNumber' is what subset's it down to a single rider? Also, what's the purpose of the join, do you want the rider's name from there or some other identifier? I've left it but if you aren't using it, it's a waste...
$GetLapData = mysql_Query("SELECT LapData.TagID, LapData.LapNumber, LapData.LapTimeInSeconds
FROM LapData
LEFT JOIN User AS u ON LapData.TagID = u.TagID
WHERE LapData.EventID = '$EventID'
ANDLapData.RaceNameID = '$RaceNameID'
AND LapData.TagID = '$RacingNumber'
ORDER BY LapData.TagID, LapData.LapNumber ASC");
$allSeries = array(); // our "return value"
$currentSeries = null; // some temp variables
$currentRider = null;
while ($row = mysql_fetch_assoc($GetLapData))
{
$loopRider = $row['TagID']; // get rider for this database row
if ($currentRider === null || $loopRider != $currentRider) // if first loop or new rider
{
if ($currentSeries !== null)
{
$allSeries[] = $currentSeries; // we have a new rider push the last one to our return array
}
$currentSeries = array(); // this is first loop or new rider, re-init current series
$currentSeries["label"] = $loopRider;
$currentSeries["data"] = array();
}
$currentSeries["data"][] = array($row['LapNumber'],$row['LapTimeinSeconds']); //push row data into object
}
$allSeries[] = $currentSeries; // last rider's data push
In the end, allSeries is an array of associative arrays per flots documentation.
Mainly:
$allSeries = [{
"label" = "tag1",
"data" = [[0,12],[1,45],[2,454]]
},{
"label" = "tag2",
"data" = [[0,122],[1,415],[2,464]]
}]
After you Json encode this, the call is:
$.plot("#placeholder", allSeries);
My Standard PHP disclaimer, I'm not a PHP programmer, I've never used it and never ever want to use it. All the above code was peiced together from quickly reading the documentation and is untested.
I have a SQLite database and am trying to graph data on a linechart using Highcharts, PHP, and Javascript. I am graphing one series per user (a user being a text value per tuple), but am running into trouble with retrieving a subsequent user via a PHP loop.
$dbhandle = sqlite_open('db/test.db', 0666, $error);
if (!$dbhandle) die ($error);
$query5 = "SELECT DISTINCT User FROM Events";
$ok0 = sqlite_query($dbhandle, $query5, $error_msg);
if (!$ok0)
{
die("dead" . $error_msg);
}
$rows = sqlite_num_rows($ok0);
echo
"for(var i=2; i<$rows; i++) // start of JS loop.
//$rows is 4; I am graphing 2 series here
{";
$array = sqlite_fetch_array($ok0, SQLITE_ASSOC); // $ok0 is the unique list
// of users. After graphing one series, I want to grab the next user to graph
echo "chart.addSeries({
name: '{$array["User"]}',
data: [";
for($i=0; $i<$diff+1; $i++)
{
$target = date("D, j M", (strtotime($_GET["start"]) + $i * 24 * 3600));
$query6 = "SELECT * FROM Events WHERE User = '{$array["User"]}' AND Start LIKE '%{$target}%'";
$result6 = sqlite_query($dbhandle, $query6);
if (!$result6) die("Cannot execute query.");
$num = sqlite_num_rows($result6);
if($i==($diff))
{
echo $num;
}
else
echo $num . ", ";
}?>],
pointStart:
<?php
$date = DateTime::createFromFormat('D M d Y', urldecode($_GET["start"]));
echo $date->getTimestamp()*1000;?>,
pointInterval: 24 * 3600 * 1000 // one day
});
<?php echo "}";?> // end of JS loop
The result does graph two additional series, but they are both the same data from the same user. It doesn't look like the loop with sqlite_fetch_array() correctly returns the next user. Can anyone see the problem here? Maybe something with the way I'm integrating Javascript with PHP?
This line of code always does the same thing every time you call it:
$query6 = "SELECT * FROM Events WHERE User = '{$array["User"]}' AND Start LIKE '%{$target}%'";
$array supposedly has a list of distinct users, but you don't show the query for $ok0. You're doing the user lookup inside this loop for($i=0; $i<$diff+1; $i++), but you use none of those variables in determining which user to fetch.
I'd like to post the correct way to look up the next user from $array, but I have no idea what the structure is. If you can't figure out how to make your $query6 unique to each user, you'll have to post more information, like a var_dump of $array or the query text of $ok0.
Maybe you just need to move this line $array = sqlite_fetch_array($ok0, SQLITE_ASSOC); inside your for loop, but then you run the risk of $i and $diff+1 disagreeing with the number of rows available from your result.
I've figured it out. I believe that due to PHP being executed server-side, the block of code within the echoed Javascript loop results in the same values when the browser executes the Javascript. The server simply echoes the string that represents the js loop, and will run the code block after. When everything is sent to the browser, the Javascript will loop normally and simply output the results of the code block twice. I've just forgone the JS loop via PHP and replaced it with a PHP loop.
I have been pulling my hair out for several days trying to get some data organized into the appropriate JSON format so that it can be plotted in a HighCharts graph.
My plan is to execute a jQuery function to call a PHP script which pulls a few columns of weather data from a MySQL database. I can re-ogranize data on the JavaScript side, but would prefer to have all of the data organization done in PHP and then have a single, correct JSON structure going into the HighCharts engine.
I am looking at weather data, so I have several columns of data sampled at every minute. The data columns I am retrieving from MySQL are: JSTimestamp (which is a unix timestamp * 1000 for JavaScript), avgOutdoorTemperature, avgIndoorTemperature, avgOutdoorHumidity, avgIndoorHumidity. I have populated each of these columns in their own array.
I can't seem to wrap my head around the PHP logic required to manipulate the data into the following JSON/array format:
[
[
[JSTimestamp1, avgOutdoorTemperature1],
[JSTimestamp2, avgOutdoorTemperature2],
[JSTimestamp3, avgOutdoorTemperature3],
[JSTimestampN, avgOutdoorTemperatureN]
],
[
[JSTimestamp1, avgIndoorTemperature1],
[JSTimestamp2, avgIndoorTemperature2],
[JSTimestamp3, avgIndoorTemperature3],
[JSTimestampN, avgIndoorTemperatureN]
],
[
[JSTimestamp1, avgOutdoorHumidity1],
[JSTimestamp2, avgOutdoorHumidity2],
[JSTimestamp3, avgOutdoorHumidity3],
[JSTimestampN, avgOutdoorHumidityN]
],
[
[JSTimestamp1, avgIndoorHumidity1],
[JSTimestamp2, avgIndoorHumidity2],
[JSTimestamp3, avgIndoorHumidity3],
[JSTimestampN, avgIndoorHumidityN]
]
]
I have populated the above structure with dummy data and it plots beautifully in HighCharts. Here's a sample demo showing what the graph will look like: http://highcharts.com/jsbin/afutef/11/edit#javascript,live
My current code is:
<?php
include_once('./include/mysqldatabase.php');
include_once('./include/mysqlresultset.php');
date_default_timezone_set('America/New_York');
$MYSQL_HOST = 'ip_address';
$MYSQL_USER = 'username';
$MYSQL_PASS = 'password';
$MYSQL_NAME = 'weatherdata';
$db = MySqlDatabase::getInstance();
try {
$conn = $db->connect($MYSQL_HOST, $MYSQL_USER, $MYSQL_PASS, $MYSQL_NAME);
}
catch (Exception $e) {
die($e->getMessage());
}
$query = "
select
RecDate,
unix_timestamp(RecDateTime)*1000 as JSTime,
avgOutdoorTemperature,
avgIndoorTemperature,
avgOutdoorHumidity,
avgIndoorHumidity
from `rollup-minute-60`
where
RecDate > 201301010000
";
$timeArray = array();
$avgOutdoorTemperatureArray = array();
$avgIndoorTemperatureArray = array();
$combinedArray = array();
$i = 0;
$seriesNames = array('Average Outdoor Temperature','Average Indoor Temperature', 'Average Outdoor Humidity', 'Average Indoor Humidity');
foreach ($db->iterate($query) as $r) {
$jstime = $r->JSTime;
$avgOutdoorTemperature = $r->avgOutdoorTemperature;
$avgIndoorTemperature = $r->avgIndoorTemperature;
$avgOutdoorHumidity = $r->avgOutdoorHumidity;
$avgIndoorHumidity = $r->avgIndoorHumidity;
$timeArray[$i] = (float)$jstime;
$avgOutdoorTemperatureArray[$i] = (float)$avgOutdoorTemperature;
$avgIndoorTemperatureArray[$i] = (float)$avgIndoorTemperature;
$avgOutdoorHumidityArray[$i] = (float)$avgOutdoorHumidity;
$avgIndoorHumidityArray[$i] = (float)$avgIndoorHumidity;
$combinedArray[$i] = array((float)$avgOutdoorTemperature, (float)$avgIndoorTemperature, (float)$avgOutdoorHumidity, (float)$avgIndoorHumidity);
$i++;
}
echo "Combined array:<br>";
echo json_encode($combinedArray);
echo "<br><br><br>";
echo "Time array:<br>";
echo json_encode($timeArray);
echo "<br><br><br>";
$arraySize = sizeof($timeArray);
$seriesNameSize = sizeof($seriesNames);
$outputJSONArray = array();
$tempArray = array();
for ($i=0; $i<$seriesNameSize; $i++) {
for ($j=0; $j<$arraySize; $j++) {
$tempArray = array();
array_push($tempArray, $timeArray[$j], $combinedArray[$j][$i]);
echo "i=".$i.", j=".$j.", tempArray: " . json_encode($tempArray) ."<br>";
$outputJSONArray[$i] = $tempArray;
}
}
echo json_encode($outputJSONArray);
?>
With the current code above, my output array is only showing the last element in $outputJSONArray instead of the multi-dimensional construct.
Can anyone help point me in the right direction? I have found a lot of good information on this site to help me get started but need a little assistance getting over the final hurdle.
Thank you!
Check Highcharts FAQ: http://docs.highcharts.com/#preprocessing-data-from-a-database
Second example tells you how could this be done:
<?php
while ($row = mysql_fetch_array($result)) {
extract $row;
$datetime *= 1000; // convert from Unix timestamp to JavaScript time
$data[] = "[$datetime, $value]";
}
?>
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
series: [{
data: [<?php echo join($data, ',') ?>]
}]
});
Thank you for the response Paweł. I have been working with the example you posted and understand it well for a single time series. However my confusion comes to the proper formatting of multiple series.
I struggled in manipulating the data on the PHP side to get the data in the correct format:
[
[
[time1, y1],
[time2, y2],
[time3, y3]
]
[
[time1, z1],
[time2, z2],
[time3, z3]
]
[
...
]
]
However, after playing with things earlier today and ultimately drawing out a solution on a whiteboard I found a solution that appears to work, and required me to traverse the collected data arrays once for each series. It may not be optimal but works well for the few thousand points I tested it with. Here is my code for reference:
$seriesNames = array('Average Outdoor Temperature','Average Indoor Temperature');
foreach ($db->iterate($query) as $r) {
$time = (float)$r->RecDateTime;
$jstime = (float)($r->Timestamp*1000);
$avgOutdoorTemperature = (float)$r->avgOutdoorTemperature;
$avgIndoorTemperature = (float)$r->avgIndoorTemperature;
$dataArray[] = array(array($jstime, $avgOutdoorTemperature), array($jstime, $avgIndoorTemperature));
}
$arraySize = sizeof($dataArray);
$seriesNameSize = sizeof($seriesNames);
for ($i=0; $i<$seriesNameSize; $i++) {
$tempArray = array();
for ($j=0; $j<$arraySize; $j++) {
$tempArray[] = $dataArray[$j][$i];
}
$outputJSONArray[] = $tempArray;
}
echo json_encode($outputJSONArray);
I suppose I could have performed multiple queries and added each series manually, but the query I ultimately intend to use is fairly intensive and would prefer to call it only once.
I am building a website where users can reserve appointments.
I am currently building a javascript app for the project, where user can pick a date from a calendar and see the available appointments. When I am building the calendar, I need to color dates by available appointments (ex. green if there's any).
In order to do that I need to iterate a javascript array that contains all available reservations. At the moment it looks something like this:
[Object, Object, Object...]
Where the object is a javascript object that contains appointment info. Here is the php service that serves the JSON:
<?php
require_once('../include/dbconnect.php');
$sql = "SELECT appointment.example,...
person.example,...
FROM appointment, person
WHERE appointment.reserved=0";
$stmt = $db->prepare($sql);
$stmt->execute();
$array = array();
while($row = $stmt->fetchObject()){
array_push($array, $row);
}
echo json_encode($array);
?>
So this finally brings us to the question.
For easier javascript array scanning, I'd need an array/object includes appointments arranged/sorted by date. Then when I am creating an element that represents the date, I can check the object for matching data. Data like this:
{
15.09.2012 : Object,
16.09.2012 : Object{
appointment1 : Object,
appointment2 : Object
}
}
In the database an appointment has an attribute "date" which is currently a string like "16.09.2012". Should I also change it to unix timestamp?
How should I change the PHP service to output a JSON object that includes appointments filed under dates?
A possible solution is to use associative arrays in php :
$assoc = array("key" => "value");
When you fetch your database records you can do something like this :
$array = array();
while($row = $stmt->fetchObject()){
$array[$row -> date] = $row;
}
echo json_encode($array);
For sorting, you can use the ksort ( http://php.net/manual/en/function.ksort.php ) php function, to sort the array by key.
Now you will have a Javascript Object and not Javascript array.
Now you can iterate the object with for .. in javascript loop ( How to Loop through plain JavaScript object with objects as members? )
You can give try as below:
$sql = "SELECT appointment.example,...
person.example,...
FROM appointment, person
WHERE appointment.reserved=0 ORDER BY appointment.date_field ASC";
$stmt = $db->prepare($sql);
$stmt->execute();
$array = array();
while($row = $stmt->fetchObject()){
$array[$row->date_field][]=$row;
array_push($array, $row);
}
echo json_encode($array);
?>
You don't need to construct an object consisting of date keys. Instead:
include the dates in your current structure and sort the array by date:
<?php
require_once('../include/dbconnect.php');
$stmt = $db->query('
SELECT DATE(appointment.datetime) AS date,
appointment.datetime,
appointment.reserved,
appointment.example, -- do you really want to send sensitive
person.example -- data about appointments to the browser?
FROM appointment JOIN person ON ...
WHERE appointment.reserved = 0 -- should this be = 1?
ORDER BY appointment.datetime
');
echo json_encode($stmt->fetchAll(PDO::FETCH_OBJ));
?>
then skip over matching days when progressing through the array:
// loop over all dates displayed in calendar
for (
currentDate = startDate, i = 0;
currentDate <= endDate;
currentDate.setDate(currentDate.getDate() + 1)
){
// determine whether the current date is booked
// and advance pointer to next date in array
for (
booked = false;
i < arr.length && arr[i].date == currentDate;
++i
) booked |= arr[i].reserved; // or just `booked = true` if query
// returned only booked appointments
// apply appropriate CSS to currentDate
// ...
}
You might even consider reducing the client-side overhead by first returning a JSON array only of booked dates (in which case the inner loop above could be replaced with a simple if statement):
SELECT DISTINCT DATE(appointment.datetime) AS date
FROM appointment JOIN person ON ...
WHERE appointment.reserved = 0 -- should this be = 1?
ORDER BY date
And then, once the user selects a date, make a further query for the bookings on that date:
SELECT appointment.datetime
FROM appointment JOIN person ON ...
WHERE appointment.reserved = 0 -- should this be = 1?
AND DATE(appointment.datetime) = ?
ORDER BY appointment.datetime