Migrating nodejs/express API from Influxdb 1x to OSS2.4

Hi, I have updated my influxdb to oss2.4 . I have an api built using nodejs and express that has endpoints that queries influxdb and responds with json.
This all worked fine with the SQL type queries in v1xx but I cannot get it to work using flux language. an example of my old code is here:

`var express = require('express');
var router = express.Router();
const Influx = require('influx');
const http = require('http');
const os = require('os');

const influx = new Influx.InfluxDB({
    host: '192.168.0.50',
    database: 'home',
    port:8086
});
module.exports=influx;

/* GET home page. */
router.get('/', function(req, res) {

  influx.query(`
      select MEAN("humidityPercentage")  from "mqtt_weather" WHERE time <= now() and time >= now() - 7d GROUP BY time(1h)
    `)
    .then(result => {
      res.json(result)
    }).catch(err => {
      res.status(500).send(err.stack)
  });
});

router.get('/current', function(req, res) {

  influx.query(`
  select "humidityPercentage" from "mqtt_weather" ORDER BY time DESC LIMIT 1

    `)
    .then(res.set({'Access-Control-Allow-Origin': '*',"Access-Control-Allow-Headers" : "Content-Type", "Access-Control-Allow-Methods": "POST,GET"}))
    .then(result => {
      res.json(result)
    }).catch(err => {
      res.status(500).send(err.stack)
  });
});

router.get('/kithum', function(req, res) {

  influx.query('select "kitHum" from "anenom" ORDER BY time DESC LIMIT 1')
    .then(res.set({'Access-Control-Allow-Origin': '*',"Access-Control-Allow-Headers" : "Content-Type", "Access-Control-Allow-Methods": "POST,GET"}))
    .then(result => {
      res.json(result)
    }).catch(err => {
      res.status(500).send(err.stack)
  });
});

module.exports = router;`

How do I modify this to use flux queries? I have tried using the examples from here

but always get this error

Cannot read properties of undefined (reading ‘then’)

Hi,
The format of the returned data is different in v1 InfluxQL comparing to v2 Flux. There are basically two options that you can follow.

You can still use InfluxQL against InfluxDB v 2.x, it requires extra configuration on InfluxDB side. You have to map v2 bucket to v1 database+retention policy, and v2 auth token to v1 user+password. There are then no changes in your code required.

If you want to switch to flux, you have to:

  1. create flux equivalents of your previous InfluxQL queries, TL;DR InfluxDB Tech Tips: Converting InfluxQL Queries to Flux Queries | InfluxData might help … you can tune flux queries easily with InfluxDB v2 builtin UI
  2. switch to influxdb v2 client and accommodate the v2 client API
    • make your express route handlers asynchronous, then await query results using await queryApi.collectRows (see influxdb-client-js/query.ts at v1.29.0 · influxdata/influxdb-client-js · GitHub) and then transform the results to v1 format. There is no “helper” OOTB that would transform v2 results to v1 results, you have to do it on your own.
    • the situation might get simpler if you could change the format of the data returned by your express server. Your results are quite simple, you shouldn’t rely upon v1 result data format anyway

Please feel free to post an issue with a detailed description of your troubles with the v2 InfluxDB client to https://github.com/influxdata/influxdb-client-js/issue.

Thanks. I tried your suggestion but I think I have an issue with mixed JS and TS. I compiled the TS to JS but the express server stops all together with that route in use. To be honest I have never used TS before. I could really do with a full working example simple node/express app to get my head around it. I am not the world’s best developer but muddle my way through.

Use this template:


const {InfluxDB} = require('@influxdata/influxdb-client')
const INFLUX_URL = 'http://localhost:8086'
const INFLUX_TOKEN = 'my-token'
const INFLUX_ORG = 'my-org'
const influxdb = new InfluxDB({url: INFLUX_URL, token: INFLUX_TOKEN})
const queryApi = influxdb.getQueryApi(INFLUX_ORG)

router.get('/whatever', async (req, res) => {
  try {
    const fluxQuery = 'buckets()' // TODO: create a real query on your own
    const fluxResult = await queryApi.collectRows(fluxQuery)
    const influxQLResult = fluxResult // TODO: transform fluxResult to influxQLResult
    res.json(influxQLResult)
  } catch (e) {
    console.error('/whatever failed: ', e)
    res.status(500).send(e.message || String(e))
  }
})


...

Thanks, that’s really helpful. Unfortunately it still stops the node server for some reason. It must be in the main app, Do I need an env set up for the above to work?
I have managed to get results using the JavaScript http template from the Git repository, I could drop the node API middleman and do it all client side ,just concerned it will be slower. Other option is start a new express app from scratch and see if that helps. The API was done as I wanted to learn something useful on Nodejs and we interact with them a lot at work, so it made sense, but querying direct from the browser may be more sensible. The work is on changing all the code to extract what I need from what’s returned. I only need the time and the field value with their keys in an array of objects. If the query could do this it would make sense. Telegraf, which I am using to send http requests to the Esp32 to get the data seems to add lots of additional info I don’t need, I guess this can be changed in the config or by using a task. A lot to learn.

Thanks for letting us know what you are trying to achieve. You can move parts of the code to run in the browser. InfluxDB authentication token gets public then, allowing everyone to execute any flux script. It might be a security concern.

No env is required

Thanks for your help, I finally got it to work as an Express API, no idea what the problem was but the error reporting wasn’t working. In case it helps someone else here is the code. I couldn’t get the mapper for collectrows to do what I wanted, so I just made some functions to do it.

var express = require('express');
var router = express.Router();
const http = require('http');
const os = require('os');
const {InfluxDB} = require('@influxdata/influxdb-client')

// You can generate an API token from the "API Tokens Tab" in the UI
const token = '*****************************'
const org = '*****************'
const bucket = 'weather'

const client = new InfluxDB({url: 'http://192.168.0.63:8086', token: token})



const queryApi = client.getQueryApi(org)


let objs = {}
let datArray = []

function objMapper (e){
  objs.time = e._time;
  objs[e._field] = e._value;
  datArray.push(objs);
  objs={};
}

router.get('/', async (req, res, next) => {

  const queryApi = client.getQueryApi(org)

  datArray = []
  
  try {
    const fluxQuery = `from(bucket:"weather") |> range(start: -1h) |> filter(fn: (r) => r._measurement == "http")` // TODO: create a real query on your own
    const fluxResult = await queryApi.collectRows(fluxQuery)
    fluxResult.forEach(objMapper)
    
    res.json(datArray)
    
  } catch (e) {
    console.error('/whatever failed: ', e)
    res.status(500).send(e.message || String(e))
  }

})


module.exports = router;