Remove first element from JSON Array in Item

Hello,

I am currently having a String item which contains an array. When this item is changed, it triggers a rule and the rule sends a HTTP Put Request with the first element in the array as body.
I do want to remove the first element in that array when I get the response, so a queue will be simulated by triggering the rule again.

Note:
This is for a nodejs local API which gets an item name and a tag and adds the tag to .items file. Any other advice on how to handle this would be great!

This is the Item

[
 {"name": "SomeItem_Status", "tag": "SomeTag"},
 {"name": "SomeItem_Status", "tag": "SomeTag"},
 {"name": "SomeItem_Status", "tag": "SomeTag"}
]

This is the rule

rule "Update item tags in webAPI"
when
    Item ItemsToModify changed
then
    var itemName = transform("JSONPATH", "$.[0].name", ItemsToModify.state.toString)
    var itemTag = transform("JSONPATH", "$.[0].tag", ItemsToModify.state.toString)
    var requestContent = '{"name": "' + itemName + '", "tag": "' + itemTag + '"}'
    sendHttpPutRequest("http://localhost:61000/addTag", "application/json", requestContent)
    /* now we should delete the first element of the array */
    ItemsToModify.sendCommand(transform("JSONPATH", "$.[1:]", ItemsToModify.state.toString))
end

Sending the request and editing the item works, but I can not find a way to remove the element. The JSONPATH returns a warning and my object is null after that.

The warning:
JsonPath expressions with more than one result are only supported for Boolean, Number and String data types, please adapt your selector.
Result: [{"name":"SomeItem_Status","tag":"SomeItem_Tag"},{"name":"SomeItem_Status","tag":"SomeItem_Tag"}]

Try using just the item with REGEX to help with the first element.

{ http="<[https://www.cdc.gov/coronavirus/2019-ncov/json/us-cases-map-data.json:30000:REGEX((.*))]" }

Perhaps you can change your approach.
What sets this Item’s state in the first place, can you change it to send a command instead? If so you could trigger your rule from command and postUpdate whatever you like without retriggering.

Well, item state is changed using the REST API.
My expected behaviour will be this:

  1. An external device will PUT to the Openhab REST API all the items where it wants to have the new tag added as a JSON array stringified to the item called ItemsToModify
  2. Rule detects state change, then proceds to send the first item in the array to the nodejs API.
  3. When it gets the response, first item should be removed from the array and step 2 should be retriggered.

So I do need the retrigger to happen.

Well, that’s the key part. Don’t alter your array until you get the response i.e. do that step 3 in some other rule triggered by the response, not in step 2

Wouldn’t the JSONPATH error be the same? The issue is altering the array, not the timing (might be an issue there too, but didn’t reach that far).

You’re modifying one Item through REST. Why not just change the tags of the Items through REST?

curl -X PUT --header "Content-Type: application/json" --header "Accept: application/json" "https://localhost:8443/rest/items/test_item/tags/test_tag"

The RESTdocs UI documents your options.

The items are created in .items files, and they can not be changed through the API. The usage of files is mandatory, unfortunately.

Yes, you can’t use the JSONPATH transformation service like that. It’s not ordinary JSONPATH, for a start it can only return a single string not an array. That’s what the error message is saying.
That makes sense because you can only post a single string to your Item anyway…

If you use a JS javascript transform instead, you will get access to JSON tools and array handling tools in one operation (but still to return a simple string).

1 Like

This solved it!
For anyone who might be interested, here is the rule:

rule "Update item tags in webAPI"
when
	Item ItemsToModify changed
then
	if(ItemsToModify.state.toString != "[]")
	{
		var itemName = transform("JSONPATH", "$.[0].name", ItemsToModify.state.toString)
		var itemTag = transform("JSONPATH", "$.[0].tag", ItemsToModify.state.toString)
		var requestContent = '{"name": "' + itemName + '", "tag": "' + itemTag + '"}'		
		var response = sendHttpPutRequest("http://localhost:61000/addTag", "application/json", requestContent)
		if(response == "true")
		{
			ItemsToModify.sendCommand(transform("JS","removeFirstElement.js", ItemsToModify.state.toString))
		}
	}
end

And here is the Javascript Transformation

(function(i) {
    var tempArray = JSON.parse(i);
	tempArray.shift();
	return (JSON.stringify(tempArray))
	
})(input)

To remove first element from array, use array shift() method. If you are using JSON, then convert the json to the array and then use the inbuilt method to remove the first item from the array.

The array shift() method removes the first element and returns that element. So, if you want to perform some operations on the removed element, then you can do that as well.