原创| 笔记| 一个月前| 阅读 15 次 | 0赞同 0反对
概述:我在做一个小型物联网应用时,使用Laravel和Thinkphp作为后端开发,结合官方网站信息和Yurun\TDEngine\TDEngineManager接口,制作了下述标准方法,,包含了建立连接、sql执行、创建表、创建子表、单条数据入库、单表多条数据入库。
我在做一个小型物联网应用时,使用Laravel和Thinkphp作为后端开发,结合官方网站信息和Yurun\TDEngine\TDEngineManager接口,制作了下述标准方法,以供有需要的朋友做开发:
PHP后端开发源码,包含了建立连接、sql执行、创建表、创建子表、单条数据入库、单表多条数据入库、多表多条数据入库等。
use Yurun\TDEngine\ClientConfig;
use Yurun\TDEngine\TDEngineManager;
class XXXX extends Model {
/**
* 要考虑两个用例:分页查询和图标连续点位
*
* @param array $input
* @return void
* @author dmakecn@163.com
* @since 2023-12-06
*/
public function initialize($input = []) {
if ($input) {
switch ($input['act']) {
case "initstable":
// 初始化超级表
return self::createStable();
case "statDataCount":
return self::statDataCount($input['start'], $input['end'], $input['table']);
case "inputdb":
// 给某个表插入数据
return self::initData($input);
case "input1dbs":
// 给某个表插入多条数据
return self::init1Datas($input);
case "inputmdbs":
// 给多张表插入多条数据
return self::initsMDatas($input);
default:
// 查询某表的数据
return self::sensorDataInit(self::type2db($input['act']), $input);
}
}
}
/**
* tdengine的查询工具
* 注意注意:这个东西是给admin用的,因为时序库主要是在图表中体现点位
* 所以原生的将分类、数据点分离是正确的,不用加工
* https://docs.taosdata.com/2.6/reference/connector/php/
*
* @param string $sql
* @return void
* @author dmakecn@163.com
* @since 2023-12-01
*/
private function tdconnector($sql = '', $datatype = 'lines') {
// 增加名称为 test 的连接配置
TDEngineManager::setClientConfig('test', new ClientConfig(config('extra.tdengine')));
// 设置默认数据库为test
TDEngineManager::setDefaultClientName('test');
// 获取客户端对象(\Yurun\TDEngine\Client)
$client = TDEngineManager::getClient();
// 执行查询
$result = $client->sql($sql);
switch ($datatype) {
case "lines":
// 获取接口原始返回数据d
return $result->getResponse();
case "pages":
// 获取分页数据中的数据段
$keys = [];
foreach ($result->getColumns() as $column) {
$k = $column->getName();
array_push($keys, $k);
}
// 获得数据集,组装成标准json格式
$list = [];
foreach ($result->getData() as $row) {
$item = [];
foreach ($keys as $kk) {
$v = $row[$kk];
if ($kk == 'ts') {
$v = date("Y-m-d H:i:s", strtotime($v));
}
$item[$kk] = $v;
}
array_push($list, $item);
}
return $list;
case "count":
// 获取分页数据总数
$result->getResponse();
foreach ($result->getData() as $row) {
return $row['total'];
}
default:
return $result->getResponse();
}
}
/**
* 时序库的2种基础用法:分页、图表折线
*
* @param [type] $table
* @param [type] $input
* @return void
* @author dmakecn@163.com
* @since 2023-12-06
*/
private function sensorDataInit($table, $input) {
$sql = '';
$data = [];
$cond = getCond(urldecode($input['c_d']));
switch ($input['datatype'] ?: 'pages') {
case "pages":
//分页类型的查询
$page = $cond['p_i'];
$limit = $cond['p_s'];
$where = 'where 1=1';
if ($cond && $cond != []) {
foreach ($cond as $k => $v) {
// 1. 排除
if (in_array($k, ['datatype', 'p_i', 'p_s'])) {
continue;
}
//1.1 当dev_id==0时就查全部
if ($k == 'dev_id' && $v == 0) {
continue;
}
// 2. 拼接where
if ($k == 'start') {
$where .= " and (ts between '" . date('Y-m-d H:i:s', $v) . "' and ";
} else if ($k == 'end') {
$where .= " '" . date('Y-m-d H:i:s', $v) . "' ) ";
} else {
$where .= " and $k='$v' ";
}
}
}
// 3. 构造sql
$page = $page ? $page : 1;
$limit = $limit ? $limit : 10;
$pagefrom = $limit * ($page - 1);
$sqllist = "select * from $table $where order by ts desc limit $pagefrom,$limit";
$sqltotal = "select count(1) as total from $table $where";
// 4. 返回结果
$data['list'] = self::tdconnector($sqllist, 'pages');
$data['count'] = self::tdconnector($sqltotal, 'count');
$data['page'] = $page;
break;
case "lines":
//组装数据图表类型
$start = $cond['start'];
$end = $cond['end'];
$sql = "select * from $table where ts between '" . date('Y-m-d H:i:s', $start) . "' and '" . date('Y-m-d H:i:s', $end) . "'";
$data = self::tdconnector($sql, 'lines');
break;
}
return getJsonCode($data);
} /**
* 查询表的数据量
*
* @param [type] $start
* @param [type] $end
* @return void
* @author dmakecn@163.com
* @since 2024-03-31
*/
public function statDataCount($start, $end, $table = '') {
if ($table == 'all') {
$stables = 'SHOW STABLES;';
$tables = self::tdconnector($stables, '')['data'];
$last = end($tables);
$sql = '';
foreach ($tables as $t) {
$sql .= "(select count(1)as rows,'$t[0]' as tablename from $t[0] ) " . ($t == $last ? ';' : 'union');
}
return self::tdconnector($sql, '');
}
$table = self::strtype2db($table);
return self::tdconnector("select count(1) as rows from $table where ts between '$start' and '$end'", '');
}
/**
* 一张表一个记录值实时登记
*
* @return void
* @author dmakecn@163.com
* @since 2025-02-18
*/
private function initData($input) {
$db = self::strtype2db($input['type']);
// 根据设备id创建子表
$res = self::writeSubtable($db . '_' . $input['dev_id'], $db, $input['tag'], $input['values']);
return getJsonCode($res);
}
/**
* 一张表多个记录值,含时间
*
* @param [type] $input
* @return void
* @author dmakecn@163.com
* @since 2025-02-18
*/
private function init1Datas($input) {
$db = self::strtype2db($input['type']);
// 根据设备id创建子表
$res = self::writeOneTable($db . '_' . $input['dev_id'], $db, $input['tag'], $input['values']);
return getJsonCode($res);
}
/**
* 多张表多个记录值【未完成】
*
* @param [type] $input
* @return void
* @author dmakecn@163.com
* @since 2025-02-18
*/
private function initsMDatas($input) {
$items = json_decode($input['items']);
$res = self::writeMultTables($items);
return getJsonCode($res);
}
/**
* 初始化创建超级表
*
* @return void
* @author dmakecn@163.com
* @since 2023-12-25
*/
private function createStable() {
// 这里字段不能用varchar、decimal等,要用binary(4n)和float,因此在设计的时候把位数想好,TAGS后面的是外键,用于定位子表
// 下述分别为 电气火灾、土壤墒情、烟雾探测、交通运输、水体、危险气体检测的超级表生成,如有其他表生成可以参考
// $example = 'CREATE STABLE IF NOT EXISTS iot_data_electric_fire (ts timestamp, data_id bigint, batch_id int, b1 int,b2 int,b3 int,b4 int,b5 int,b6 int,b7 int) TAGS (dev_id int,gateway_id int,project_id int);';
// $example = 'CREATE STABLE IF NOT EXISTS iot_data_land (ts timestamp, data_id bigint, batch_id int, j1 int,j2 int,j3 int,j4 int,j5 int,j6 int,j7 int) TAGS (dev_id int,gateway_id int,project_id int);';
// $example = 'CREATE STABLE IF NOT EXISTS iot_data_smoke (ts timestamp, data_id bigint, batch_id int, a1 int,a2 int,a3 int,a4 int,a5 int) TAGS (dev_id int,gateway_id int,project_id int);';
// $example = 'CREATE STABLE IF NOT EXISTS iot_data_transport (ts timestamp, data_id bigint, batch_id int, t1 int,t2 int,t3 int,t4 int,t5 int) TAGS (dev_id int,gateway_id int,project_id int);';
// $example = 'CREATE STABLE IF NOT EXISTS iot_data_water (ts timestamp, data_id bigint, batch_id int, i1 float,i2 float,i3 float,i4 float,i5 float,i6 float,i7 float) TAGS (dev_id int,gateway_id int,project_id int);';
// $example = 'CREATE STABLE IF NOT EXISTS iot_data_harmfulgas (ts timestamp, data_id bigint, batch_id int, h1 int,h2 int,h3 int,h4 int,h5 int,h6 int,h7 int) TAGS (dev_id int,gateway_id int,project_id int);';
// return self::tdconnector($example, '');
return getJsonCode(true, '本项目已初始化超级表');
}
/**
* 创建超级表的子表并插入数据
*
* @param [type] 子表的名
* @param [type] 超级表的名
* @param [type] 外键表示
* @param [type] 参数
* @return void
* @author dmakecn@163.com
* @since 2023-12-25
*/
private function writeSubtable($sname, $name, $tag, $value) {
// 承接上一个function,d1001属于子表的别名,用英文和编号的好处是规范,using后面这一坨,就是上述的外键,我想应该是方便快速查询吧
// 案例同时做了2件事:用超级表的结构,向tags的标识内写入了数据
//举例: INSERT INTO d1001 USING STABLE VALUES (1538548684000, 10.2, 220, 0.23) (1538548696650, 10.3, 218, 0.25);
$example = "INSERT INTO $sname USING $name TAGS ($tag) VALUES (NOW, $value);";
return self::tdconnector($example, '');
}
/**
* 写入单表:一条记录不能超过 48KB,一条 SQL 语句总长度不能超过 1MB。
* https://docs.taosdata.com/develop/insert-data/sql-writing/
*
* @return void
* @author dmakecn@163.com
* @since 2023-12-25
*/
public function writeOneTable($sname, $name, $tag, $values) {
// 承接上一个function,给子表写数据,属于直接写咯,tags就没有用到,随便写咯
// $example = 'INSERT INTO d1001 VALUES (ts1, 10.2, 220, 0.23) (ts2, 10.3, 218, 0.25);';
$example = "INSERT INTO $sname USING $name TAGS ($tag) VALUES $values;";
return self::tdconnector($example, '');
}
/**
* 写入多表:一条记录不能超过 48KB,一条 SQL 语句总长度不能超过 1MB。
* https://docs.taosdata.com/develop/insert-data/sql-writing/
*
* @param array $items 每张表的sname,name,tag,values
* @return void
* @author dmakecn@163.com
* @since 2023-12-25
*/
public function writeMultTables($items) {
$sql = "INSERT INTO";
foreach ($items as $i) {
$db = self::strtype2db($i->type);
$sname = $db . '_' . $i->dev_id;
$name = $db;
$tag = $i->tag;
$values = $i->values;
$sql .= " $sname USING $name TAGS ($tag) VALUES $values";
}
$sql .= ";";die($sql);
return self::tdconnector($sql, '');
// 同时向多个子表写入数据
// $example = 'INSERT INTO d1001 VALUES (ts1, 10.3, 219, 0.31) (ts2, 12.6, 218, 0.33) d1002 VALUES (ts3, 12.3, 221, 0.31);';
// https://docs.taosdata.com/2.6/reference/connector/php/
}
}
如果前端通过post接口调用可参考下述方式:
// 47 初始化tdengine数据库表
// JsonAPI({ 'c': 'xxx', 'a': 'xxx', 'data': 'act=initstable'}, function (res) {
// console.log(res);
// }, api);
// 48 传值到某个tdengine表:一张表一个记录值实时登记
// JsonAPI({ 'c': 'xxx', 'a': 'xxx', 'data': 'act=inputdb&type=smoke&dev_id=1&tag=1,2,3&values=1,2,3,4,5,6,7'}, function (res) {
// console.log(res);
// }, api);
// 49 1个表传多个值带时间的
// JsonAPI({ 'c': 'xxx', 'a': 'xxx', 'data': "act=input1dbs&type=smoke&dev_id=1&tag=1,2,3&values=('2025-02-18 21:17:55.596',11,2,3,4,5,6,7)('2025-02-18 21:15:55.596',12,2,3,4,5,6,7)('2025-02-18 21:10:55.596',13,2,3,4,5,6,7)"}, function (res) {
// console.log(res);
// }, api);
// 50 多个表传多个值带时间的
// var multdatas=[
// {type:'soil',dev_id:1,tag:'1,2,3',values:"('2025-02-11 21:17:55.596',11,11,1,2,3,4,5,6,7)('2025-02-12 21:15:55.696',12,12,1,2,3,4,5,6,7)('2025-02-13 21:10:55.996',13,13,1,2,3,4,5,6,7)"},
// {type:'water',dev_id:2,tag:'1,2,3',values:"('2025-02-14 21:17:55.597',11,11,1,2,3,4,5,6,7)('2025-02-15 21:15:55.697',12,12,1,2,3,4,5,6,7)('2025-02-16 21:10:55.997',13,13,1,2,3,4,5,6,7)"},
// {type:'harmfulgas',dev_id:3,tag:'1,2,3',values:"('2025-02-17 21:17:55.597',11,11,1,2,3,4,5,6,7)('2025-02-18 21:15:55.898',12,12,1,2,3,4,5,6,7)('2025-02-19 21:10:55.998',13,13,1,2,3,4,5,6,7)"}];
// JsonAPI({ 'c': 'xxx', 'a': 'xxx', 'data': "act=inputmdbs&items="+JSON.stringify(multdatas)}, function (res) {
// console.log(res);
// }, api);
// 51 查询tdengine中的数据条数 table all或者表type
JsonAPI({ 'c': 'xxx', 'a': 'xxx', 'data': 'act=statDataCount&start=2025-1-1&end=2025-2-19&table=smoke'}, function (res) {
console.log(res);
}, api);
以上就是我使用php管理tdengine的实操代码,有需要的朋友自取。
本频道需要登陆后才能评论,请登录