InfluxDB: Query with NULL fallback (like COALESCE) - influxdb

The following Flux query (using InfluxDB 2.6) works, but the IF/ELSE looks strange. Is there a more simple way, like a COALESCE function? I want to treat a field () as ZERO if it's NULL.
from(bucket: "PV")
|> map(fn: (r) => ({
r with autarky: 100.0 * (1.0 - (r.grid_power_plus / (r.house_power +
(if r.wallbox_charge_power > 0 then r.wallbox_charge_power else 0.0))))
}))
|> keep(columns: ["_time", "autarky"])
I would like something like that (which is invalid):
...
|> map(fn: (r) => ({
r with autarky:
100.0 * (1.0 - (r.grid_power_plus / (r.house_power + COALESCE(r.wallbox_charge_power, 0.0))))
}))
...

Related

Dynamic Filtering using variable in filter function in Flux

Using the quantile function, I was able to get 95 % percentile value in a stream.
Now, i want to filter records which lie below the 95% percentile.
hence, I loop over my recods and filter records which lie below the percentile.
However, at this topic I get error –
Please find code below –
percentile = totalTimeByDoc
|> filter(fn: (r) => r["documentType"] == "PurchaseOrder")
|> group(columns:["documentType"])
// |> yield()
|> quantile(column: "processTime", q: 0.95, method: "estimate_tdigest", compression: 9999.0)
|> limit(n: 1)
|> rename(columns: {processTime: "pt"})
Gives me data – >
0 PurchaseOrder 999
Now, I try to loop over my records and filter -
percentile_filered = totalTimeByDoc
|> filter(fn: (r) => r["documentType"] == "PurchaseOrder")
|> filter(fn: (r) => r.processTime < percentile[0]["pt"])
|> yield()
Where, totalTimeByDoc is like below –
|0|PurchaseOrder|testpass22PID230207222747-1|1200|
|1|PurchaseOrder|testpass22PID230207222747-2|807|
|2|PurchaseOrder|testpass22PID230207222934-1|671|
|3|PurchaseOrder|testpass22PID230207222934-2|670|
I get following error from above query –
error #116:41-116:51: expected [{A with pt: B}] (array) but found stream[{A with pt: B}]
You are only missing column extraction from percentile stream. Have a look at Extract scalar values. In this very case, you could do
percentile = totalTimeByDoc
|> ...
|> rename(columns: {processTime: "pt"})
|> findColumn(fn: (key) => true, column: "pt")
percentile_filtered = totalTimeByDoc
|> filter(fn: (r) => r["documentType"] == "PurchaseOrder")
|> filter(fn: (r) => r.processTime < percentile[0])
|> yield()

Append calculated field (percentage) and combine with results from different datasets, in Influx Flux

I'm struggling with an Influx 2 query in Flux on how to join and map data from two differents sets (tables) into a specific desired output.
My current Flux query is this:
data = from(bucket: "foo")
|> range(start:-1d)
|> filter(fn: (r) => r._measurement == "io")
|> filter(fn: (r) => r["device_id"] == "12345")
|> filter(fn: (r) => r._field == "status_id" )
# count the total points
totals = data
|> count(column: "_value")
|> toFloat()
|> set(key: "_field", value: "total_count")
# calculate the amount of onlines points (e.g. status = '1')
onlines = data
|> filter(fn: (r) => r._value == 1)
|> count(column: "_value")
|> toFloat()
|> set(key: "_field", value: "online_count")
union(tables: [totals, onlines])
This returns as output:
[{'online_count': 58.0}, {'total_count': 60.0}]
I would like to have appended to this output a percentage calculated from this. Something like:
[{'online_count': 58.0}, {'total_count': 60.0}, {'availability': 0.96666667}]
I've tried combining this using .map(), but to no avail:
# It feels like the map() is what I need, but can't find the right
# combination with .join/union(), .map(), .set()., .keep() etc.
union(tables: [totals, onlines])
|> map(fn: (r) => ({ r with percentage_online: r.onlines.online_count / r.totals.total_count * 100 }))
How can I append the (calculated) percentage as new field 'availability' in this Flux query?
Or, alternatively, is there a different Flux query approach to achieve this outcome?
N.B. I am aware of the Calculate percentages with Flux article from the docs, which I can't get working into this specific scenario. But it's close.

InfluxDB 2.0 multiple aggregations

I'm new to InfluxDB 2.0 and I used InfluxDB 1.6 for few months.
I'm trying to rewrite my queries to use flux language and I encountered problem with multiple aggregations.
Earlier I used this query:
select
max(val_max) as val_max,
min(val_min) as val_min,
last(val_close) as val_close,
first(val_open) as val_open
from candle
where time > '{t}' and interval = '{interval}'
group by currency_id
What would this query look like in flux?
I had similar query to rewrite before, that looked liked this:
select "
max(last_price) as val_max,
min(last_price) as val_min,
first(last_price) as val_open,
last(last_price) as val_close
from ticker
where time > '{t}'
group by currency_id
and after rewriting to flux it looks like this:
data = from(bucket: "{self.bucket}")
|> range(start: {min_time})
|> filter(fn: (r) =>
r._measurement == "ticker" and
r._field == "last_price"
)
|> group(columns: ["currency_id"])
val_max = data
|> max()
|> set(key: "_field", value: "val_max")
val_min = data
|> min()
|> set(key: "_field", value: "val_min")
val_open = data
|> first()
|> set(key: "_field", value: "val_open")
val_close = data
|> last()
|> set(key: "_field", value: "val_close")
union(tables: [val_max, val_min, val_open, val_close])
|> pivot(rowKey:["currency_id"], columnKey: ["_field"], valueColumn: "_value")
The difference is that I use one column for aggregation in one query and multiple columns in another

Aggregate Flux Query in Influxdb

I am new to Influxdb. I am using 1.8+ Influxdb and com.influxdb:influxdb-client-java:1.11.0. I have a below measurement
stocks {
(tag) symbol: String
(field) price: Double
(field) volume: Long
(time) ts: Long
}
I am trying to query the measurement with a 15 min window. I have the below query
"from(bucket: \"test/autogen\")" +
" |> range(start: -12h)" +
" |> filter(fn: (r) => (r[\"_measurement\"] == \"$measurementName\" and r[\"_field\"] == \"volume\"))" +
" |> cumulativeSum(columns: [\"_value\"])" +
" |> window(every: 15m, period: 15m)"
I believe that the above query calculates the cumulative sum over the data and returns just the volume field. However, I want the entire measurement including price, symbol, and ts along with the cumulative sum of the volume in a single flux query. I am not sure how to do this. Any help is appreciated. Thanks.
Thanks to Ethan Zhang. Flux output tables use a vertical (column-wise) data layout for fields.
Note that the price and the volume fields are stored as two separate rows.
To achieve the result you can use a function called v1.fieldsAsCols() to convert the table from a vertical layout back to the horizontal layout. Here is a link to its documentation: https://docs.influxdata.com/influxdb/v2.0/reference/flux/stdlib/influxdb-v1/fieldsascols/
Hence query can be rewritten as follows: sample query 1
from(bucket: \"test/autogen\")
|> range(start: -1h)
|> filter(fn: (r) => r["_measurement"] == "stocks"))
|> v1.fieldsAsCols()
|> group()
|> cumulativeSum(columns: ["volume"])
|> window(every: 15m, period: 15m)
Another approach is using pivot: sample query 2
from(bucket: \"test/autogen\")
|> range(start: -1h)
|> filter(fn: (r) => r["_measurement"] == "stocks")
|> pivot(rowKey:[\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\")
|> group()
|> cumulativeSum(columns: ["volume"])
|> window(every: 15m, period: 15m)

Ternary operator in Influx flux

I am doing a join in influx to get the first and last values for a interval and then getting the difference.
Preset = 600
FirstValues = from(bucket: "Historian/oneday")
|> range(start: dashboardTime)
|> filter(fn: (r) =>
r._measurement == "TestMeasurement" and
r._field =="Value" and
r.Loc=="TXS"
)
|>window(every:15m)
|>first()
LastValues = from(bucket: "Historian/oneday")
|> range(start: dashboardTime)
|> filter(fn: (r) =>
r._measurement == "TestMeasurement" and
r._field =="Value" and
r.Loc=="TXS"
)
|>window(every:15m)
|>last()
CombinedValues = join (
tables:{first:FirstValues,last:LastValues},
on:["_stop","_start"]
)
totaliser = CombinedValues
|>map(fn: (r) => ({
_time: r._start,
//Want to do this, r._value_first < r._value_last ? Preset : r._value_first
_value: r._value_first - r._value_last
}))
totaliser
|>window(every:inf)
This works fine till the time difference returns a positive number.
But if the 1st value from join returns is less than 2nd value , I want to update that with a perset value.
Ex:
Preset = 600
totaliser = CombinedValues
|>map(fn: (r) => ({
_time: r._start,
//Want to do this, r._value_first < r._value_last ? Preset : r._value_first
_value: r._value_first - r._value_last
}))
Conditional logic is pretty new to Flux, but it does exist. Currently there is only if, else if, and else:
// Pattern
if <condition> then <action> else <alternative-action>
// Example
if color == "green" then "008000" else "ffffff"
But this will be expanded with time.
https://v2.docs.influxdata.com/v2.0/query-data/guides/conditional-logic/

Resources