LCB
LCB

Reputation: 87

How to limit values (clamp) in JSON with JQ?

I have an application which writes/concatenates data into JSON, and then displays/graphs it via dygraphs. At times, various events can cause the values to go out of range. That range is user-subjective, so clamping that range at run-time is not the direction I am wishing to go.

I believe jq can help here - ideally I would be able to search for a field > x and if it is > x, replace it with x. I've gone searching for jq examples and not really found anything that's making sense to me yet.

I have spent a bit of time on this but not been able to make anything do what I think it should do ... at all. Like, I don't have bad code to show you because I've not made it do anything yet. I sincerely hope what I am asking is narrowed down enough for someone to be able to show me, in context, so I can extend it for the larger project.

Here's a line which I would expect to be able to modify:

{"cols":[{"type":"datetime","id":"Time","label":"Time"},{"type":"number","id":"Room1Temp","label":"Room One Temp"},{"type":"number","id":"Room1Set","label":"Room One Set"},{"type":"string","id":"Annot1","label":"Room One Note"},{"type":"number","id":"Room2Temp","label":"Room Two Temp"},{"type":"number","id":"Room2Set","label":"Room Two Set"},{"type":"string","id":"Annot2","label":"Room Two Note"},{"type":"number","id":"Room3Temp","label":"Room Three Temp"},{"type":"number","id":"State","label":"State"},{"type":"number","id":"Room4Temp","label":"Room Four Temp"},{"type":"number","id":"Quality","label":"Quality"}],"rows":[
{"c":[{"v":"Date(2019,6,4,20,31,13)"},{"v":68.01},{"v":68.0},null,{"v":62.02},{"v":55.89},null,null,{"v":4},{"v":69.0},{"v":1.052}]}]}

I'd want to do something like:

if JSONFile.Room2Set < 62
    set Room2Set = 62

Here's a larger block of JSON which is the source of the chart shown below:

Example Chart

Upvotes: 0

Views: 1128

Answers (2)

peak
peak

Reputation: 116780

With an invocation such as:

jq --arg col Room2Set --argjson mx 72  --argjson mn 62 -f clamp.jq input.json

where clamp.jq contains:

def clamp: if . > $mx then $mx elif . < $mn then $mn else . end;

(.cols | map(.id) | index($col)) as $ix
| .rows[].c[$ix].v |= clamp

the selected cells should be "clamped".

Upvotes: 1

Jeff Mercado
Jeff Mercado

Reputation: 134881

With a function clamp functions defined like so (in your ~/.jq file or inline):

def clamp_min($minInc): if . < $minInc then $minInc else . end;
def clamp_max($maxInc): if . > $maxInc then $maxInc else . end;
def clamp($minInc; $maxInc): clamp_min($minInc) | clamp_max($maxInc);

And with that data, you'll want to find the corresponding cells for each row and modify the value.

$ jq --arg col "Room2Set" --argjson max '62' '
def clamp_max($maxInc): if . > $maxInc then $maxInc else . end;
(INDEX(.cols|to_entries[]|{id:.value.id,index:.key};.id)) as $cols
  | .rows[].c[$cols[$col].index] |= (objects.v |= clamp_max($max))
' input.json

Upvotes: 2

Related Questions