原创| 笔记| 一个月前| 阅读 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的实操代码,有需要的朋友自取。
本频道需要登陆后才能评论,请登录