How to replace an empty InfluxDB query result with a single value for the single stat visualization - influxql

I'm using the new InfluxDB2 and the flux query language to retrieve docker stats from my bucket. I want to display the uptime of a container in a single stat widget.
For this I use the following query:
from(bucket: "docker")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "docker_container_status")
|> filter(fn: (r) => r._field == "uptime_ns")
|> filter(fn: (r) => r.container_name == "some_container")
|> window(period: v.windowPeriod)
|> last()
Unfortunately, the container wasn't online in the past time range, therefore I get a "No results" displayed. Instead I would like to display a 0 value or a text like "Not online".
How can I achieve this?

Try this query, when there is no data, it should use 0.0 to fill
from(bucket: "docker")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "docker_container_status")
|> filter(fn: (r) => r._field == "uptime_ns")
|> filter(fn: (r) => r.container_name == "some_container")
|> aggregateWindow(every: v.windowPeriod, fn: (tables=<-, column="_value") =>
tables |> last(column) |> sum(column))
|> fill(value: 0.0)

If you are using Grafana you can use the option for "No value" to select what you want displayed if there are no results / No Data from your query.

Related

How to formulate conditional flux query

My Influxdb 2 measurement contains a boolean field. I would like to formulate a query that outputs all rows where the field's value is true. An if condition in a filter line does not work.
In detail: I have workout data that includes the boolean field "isIndoor". I want to visualize all values in my dashboard if that field is not true. (I can rename/filter/map values/fields in later steps.)
from(bucket: "mydata")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => if r._boolean == true then
// use all the fields
else
// actually, there shouldn't be an 'else' but Flux insists on it
)
// further treatment and filtering
How can this be accomplished?
New edit: I found out that by pivoting the data I can use a filter:
from(bucket: "mydata")
|> range(start: v.timeRangeStart, stop:v.timeRangeStop)
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> filter(fn: (r) => r["isIndoor"] == true)
Regrettably, now Grafana no longer recognized the output as graphable. I am now considering to empty the bucket and fill it with my data again but use the boolean value as a tag.
It's simple. If your condition == true then return true. In else case just return false
|> filter(fn: (r) => if myBool == true then true else false )
UPD:
|> filter(fn: (r) => r.isIndoor == true)

How to create regular expresion from Grafana variables. Influx 2.0DB

I have this query that pulls branch information from GIT. I would like to be able to filter the data by the variable "epic". In Grafana, I have the epic data pulled from the database and it can be selected from a dropdown list witch checkbox for each epic (multiselect).
from(bucket: "my_bucket")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "my_measure")
|> filter(fn: (r) => r["_field"] == "Score")
|> filter(fn: (r) => r["epic"] == "${epic_db}")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
But when i select more than one epic on list, i got this:
|> filter(fn: (r) => r["epic"] == "{epic-1,epic-2}")
Which is not working like the SQL IN statement (WHERE epic IN (epic1, epic2, etc).
The thing that is working for me, is to build the regex like this
filter(fn: (r) => r["epic"] =~ /epic1|epic2|epic3/
But i have no idea, how to build such a regex, by using this drop-down-check-list with variables in Grafana. I was trying all that stuff like:
"/${epic_db}/"
But is not working. Any ideas, how to make it possible using InfluxDB2.0 with Flux?
Have a look at the variable formatting options documentation here.
Basically grafana allows you to choose how the variable is formatted in your query. In your case you can do something like this:
from(bucket: "my_bucket")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "my_measure")
|> filter(fn: (r) => r["_field"] == "Score")
|> filter(fn: (r) => r["epic"] =~ /${epic_db:regex}/)
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
This way you can use the build in regex functionality of the flux query language.

Grafana + InfluxDB Flux - query for displaying multi-select variable inputs

We've set up a Grafana cloud + InfluxDB 2.0 (Flux language) cloud instance. As part of this, we've created a custom variable list with "device IDs", called devices.
In a panel, we wish to display parameter data where the user can select one or more device IDs from the devices list to have them displayed in the panel. This works fine for single device ID selection, but not for multiple devices.
How should the query be modified to display data from a variable number of devices based on a multi-select entry in the dropdown in Grafana?
from(bucket: "test-bucket-new")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "${devices}")
|> filter(fn: (r) => r["_field"] == "Speed")
|> aggregateWindow(every: v.windowPeriod, fn: mean)
|> yield(name: "mean")
It seems the below solves it:
from(bucket: "test-bucket-new")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => contains(value: r["_measurement"], set: ${devices:json}))
|> filter(fn: (r) => r["_field"] == "Speed")
|> aggregateWindow(every: v.windowPeriod, fn: mean)
|> yield(name: "mean")

Phoenix form validation check not showing up but non-null constraint from postgres

When trying to build form validations my error shows up in the form when I use a username exceeding 20 char, but not when I enter nothing. I get a violates non-null constraint Postgres.Error view.
# user.ex
def changeset(model, params \\ %{}) do
model
|> cast(params, ~w(name username), [])
|> validate_length(:username, min: 1, max: 20)
end
Which probably is because of the migration:
def change do
create table(:users) do
add :name, :string
add :username, :string, null: false
add :password_hash, :string
timestamps
end
create unique_index(:users, [:username])
end
Going through the Programming Phoenix book, which is unfortunately getting a little outdated, I can't find a quick solution to this problem.
Somehow the Postgres shouldn't come before the validation checks. Any idea on how to make this error go away?
If it doesn't work, I assume you're using Phoenix 1.3, so try changing this code
def changeset(model, params \\ %{}) do
model
|> cast(params, ~w(name username), [])
|> validate_length(:username, min: 1, max: 20)
end
With this:
def changeset(model, params \\ %{}) do
model
|> cast(params, ~w(name username))
|> validate_required([:username])
|> validate_length(:username, min: 1, max: 20)
end
You can check more details in documentation of Ecto.Changeset.validate_required/3.
Hope that helps!

Why am I not able to cast the associations in the changeset?

I am trying to perform a transaction where I replace unique position values. When I reinsert the shows, the episodes don't attach even though I have preloaded them with the show and I am using cast_assoc in the changeset. Below are the files:
show_controller.ex
original_show = Repo.get!(Show, id)
|> Repo.preload(:episodes)
old_position = original_show.position
%{"position" => new_position} = show_params
new_position = String.to_integer(new_position)
query = from(s in Show, where: s.position <= ^new_position, where: s.position > ^old_position)
shows = Repo.all(query) |> Repo.preload(:episodes) |> Enum.sort(&(&1.position < &2.position))
result = Repo.transaction(fn ->
Repo.delete!(original_show)
Repo.delete_all(query)
Enum.each shows, fn show ->
show = Map.put(show, :position, show.position - 1)
changeset = Show.changeset(show)
case Repo.insert(changeset) do
{:ok, show} -> show
{:error, changeset} -> Repo.rollback(changeset)
end
end
changeset = Show.changeset(original_show, new_show_params)
case Repo.insert(changeset) do
{:ok, show} -> show
{:error, changeset} -> Repo.rollback(changeset)
end
end)
show.ex
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:title, :position, :shuffle_episodes])
|> cast_attachments(params, [:large_artwork_url, :parallax_artwork_url])
|> cast_assoc(:episodes)
|> validate_required([:title, :position, :large_artwork_url, :parallax_artwork_url, :shuffle_episodes])
|> unique_constraint(:position)
end