Logic question in the Web Dev module

I am passing a list of Tags, start date and end date to the “queryTagHistory” function.

tagList = ['[default]RECEITA/BRel/BRel_0_/BatchId.value',
'[default]RECEITA/BRel/BRel_0_/NumFicha.value']

startTime = request['params']['inicio']
endTime = request['params']['fim']
			
tags = system.tag.queryTagHistory(paths=tagList, startDate=startTime, endDate=endTime, returnSize=3, aggregationMode="LastValue", returnFormat='Wide')

return {'json': system.util.jsonEncode(tags)}

see the result below:

How can I implement a for to loop through this list and return the data as follows:

{
    "result3": [
        {
            "value2": 0,
            "value1": "Jun 23, 2022, 7:25:05 AM",
            "value3": 0
        }
    ],
    "result2": [
        {
            "value2": 0,
            "value1": "Jun 19, 2022, 7:21:49 AM",
            "value3": 0
        }
    ],
    "result1": [
        {
            "value2": 0,
            "value1": "Jun 15, 2022, 7:18:33 AM",
            "value3": 0
        }
    ]
}

I’m trying something like:

headers = ['result1', 'result2', 'result3']
	data =[]
	for tag in tags:
		data.append([tag.value])
	
	ds = system.dataset.toDataSet(headers,data)
	convertData = system.dataset.toPyDataSet(ds)

If anyone can help me

We can’t see your ‘result’; was it a screenshot or an error message or something?

I was unable to publish the screenshot, I updated the post.

It’s not clear - are you trying to do this in a general purpose way, or will you only ever have these two tags and three output rows?

Also, are you married to that output format? It’s not particularly helpful to a consumer. Why not something like:

{
	"tagPath": {
		"value": value,
		"quality": quality,
		"timestamp": timestamp,
	}
}

I’m trying to do it in a general way.

Let’s suppose that I have a class called Revenue and I have the following attributes, Id, Date, FileNumber and Volume.

I have these 4 Historicized Tags, I want to consume this data via Web Server Json, creating an object structure, for example:


{
"receita": {
                 "id": 1,
                 "date": "Jun 15, 2022, 7:18:33 AM",
                 "fileNumber": 189,
                 "volume": 12.321
}
}

In short, I want to pass the start and end date in the url and associate the result in an object within this range.

try this:

columns = [col['name'] for col in data['columns']]
result = [dict(zip(columns, row)) for row in data['rows']]

edit: Note that this creates a list of dicts, not a dict of dicts.
I believe in this case, having a dict as your basic data structure is pointless. The keys are not meaningful, and since dicts are unordered you’d have to go and check each inner dict timestamp to figure out the original order.
A list seems more appropriate.
If you REALLY want a dict, here’s how:

data = {
	'columns': [
		{'name': "foo"}, {'name': "bar"}, {'name': "baz"}
	],
	'rows': [
		["foo1", "bar1", "baz1"],
		["foo2", "bar2", "baz2"],
		["foo3", "bar3", "baz3"]
	]
}

columns = [col['name'] for col in data['columns']]
result = {"result{}".format(i): dict(zip(columns, row)) for i, row in enumerate(data['rows'])}

import json
print(json.dumps(result, indent=2))

# prints this:
#{
#  "result0": {
#    "foo": "foo1", 
#    "bar": "bar1", 
#    "baz": "baz1"
#  }, 
#  "result2": {
#    "foo": "foo3", 
#    "bar": "bar3", 
#    "baz": "baz3"
#  }, 
#  "result1": {
#    "foo": "foo2", 
#    "bar": "bar2", 
#    "baz": "baz2"
#  }
#}
2 Likes

Awesome, I tested this example and it worked perfectly.

Now I’m breaking my head with a detail, when I pass the variable with the value ready, as in the example below, it works perfectly.

data = {
	    "columns": [
	        {
	            "name": "t_stamp",
	            "type": "java.sql.Timestamp"
	        },
	        {
	            "name": "RECEITA/BRel/BRel_0_/BatchId.value",
	            "type": "java.lang.Long"
	        },
	        {
	            "name": "RECEITA/BRel/BRel_0_/NumFicha.value",
	            "type": "java.lang.Long"
	        }
	    ],
	    "rows": [
	        [
	            "Jun 15, 2022, 7:15:33 AM",
	            0,
	            1644
	        ],
	        [
	            "Jun 15, 2022, 7:41:29 AM",
	            0,
	            1644
	        ],
	        [
	            "Jun 15, 2022, 8:07:25 AM",
	            0,
	            1644
	        ]
	    ]
	}
	columns = [col['name'] for col in data['columns']]
	result = {"result{}".format(i): dict(zip(columns, row)) for i, row in enumerate(data['rows'])}
	
	
	return {'json': system.util.jsonEncode(tags)}

But when I try to pass the value that I get from the queryTAG, it returns an error.

I’ve tried converting the result into several values, but without success.

	tagList = ['[default]RECEITA/BRel/BRel_0_/BatchId.value',
		'[default]RECEITA/BRel/BRel_0_/NumFicha.value']
	
	startTime = request['params']['inicio']
	endTime = request['params']['fim']
				
	tags = system.tag.queryTagHistory(paths=tagList, startDate=startTime, endDate=endTime, returnSize=3, aggregationMode="LastValue", returnFormat='Wide')
	
	data = tags
	
	columns = [col['name'] for col in data['columns']]
	result = {"result{}".format(i): dict(zip(columns, row)) for i, row in enumerate(data['rows'])}
	
	
	return {'json': system.util.jsonEncode(tags)}

image

You don’t need to call jsonEncode when you’re returning json from webdev. Just return {'json': yourPythonDictionaryOrList}. (And if you get a 500 error from webdev, check your gateway logs to see what’s wrong).

Here’s the code and the error

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 12, in doGet TypeError: 'com.inductiveautomation.ignition.gateway.datasource.BasicStreamingDataset' object is unsubscriptable
at org.python.core.Py.TypeError(Py.java:236)
at org.python.core.PyObject.__finditem__(PyObject.java:653)
at org.python.core.PyObjectDerived.__finditem__(PyObjectDerived.java:920)
at org.python.core.PyObject.__getitem__(PyObject.java:717)
at org.python.core.PyObjectDerived.__getitem__(PyObjectDerived.java:960)
at org.python.pycode._pyx308.doGet$1(:16)
at org.python.pycode._pyx308.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:306)
at org.python.core.PyFunction.function___call__(PyFunction.java:474)
at org.python.core.PyFunction.__call__(PyFunction.java:469)
at org.python.core.PyFunction.__call__(PyFunction.java:464)
at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:831)
at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:813)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runFunction(ProjectScriptLifecycle.java:806)
at com.inductiveautomation.webdev.gateway.handlers.PythonResourceHandler.doRequest(PythonResourceHandler.java:294)
at com.inductiveautomation.webdev.gateway.handlers.PythonResourceHandler.doGet(PythonResourceHandler.java:540)
at com.inductiveautomation.webdev.gateway.servlets.WebDevDispatch.doGet(WebDevDispatch.java:132)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at com.inductiveautomation.webdev.gateway.servlets.WebDevDispatch.service(WebDevDispatch.java:118)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at com.inductiveautomation.ignition.gateway.bootstrap.MapServlet.service(MapServlet.java:86)
at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1450)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1631)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at com.inductiveautomation.catapult.handlers.RemoteHostNameLookupHandler.handle(RemoteHostNameLookupHandler.java:121)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:322)
at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException: TypeError: 'com.inductiveautomation.ignition.gateway.datasource.BasicStreamingDataset' object is unsubscriptable
... 62 common frames omitted

Change data = tags to data = system.dataset.toPyDataSet(tags).

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 12, in doGet TypeError: com.inductiveautomation.ignition.common.script.builtin.DatasetUtilities$PyDataSet indices must be integers
at org.python.core.Py.TypeError(Py.java:236)
at org.python.core.SequenceIndexDelegate.checkIdxAndFindItem(SequenceIndexDelegate.java:74)
at org.python.core.SequenceIndexDelegate.checkIdxAndGetItem(SequenceIndexDelegate.java:61)
at org.python.core.PySequence.seq___getitem__(PySequence.java:378)
at org.python.core.PySequence.__getitem__(PySequence.java:374)
at org.python.pycode._pyx466.doGet$1(:15)
at org.python.pycode._pyx466.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:306)
at org.python.core.PyFunction.function___call__(PyFunction.java:474)
at org.python.core.PyFunction.__call__(PyFunction.java:469)
at org.python.core.PyFunction.__call__(PyFunction.java:464)
at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:831)
at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:813)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runFunction(ProjectScriptLifecycle.java:806)
at com.inductiveautomation.webdev.gateway.handlers.PythonResourceHandler.doRequest(PythonResourceHandler.java:294)
at com.inductiveautomation.webdev.gateway.handlers.PythonResourceHandler.doGet(PythonResourceHandler.java:540)
at com.inductiveautomation.webdev.gateway.servlets.WebDevDispatch.doGet(WebDevDispatch.java:132)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at com.inductiveautomation.webdev.gateway.servlets.WebDevDispatch.service(WebDevDispatch.java:118)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at com.inductiveautomation.ignition.gateway.bootstrap.MapServlet.service(MapServlet.java:86)
at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1450)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1631)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at com.inductiveautomation.catapult.handlers.RemoteHostNameLookupHandler.handle(RemoteHostNameLookupHandler.java:121)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:322)
at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException: TypeError: com.inductiveautomation.ignition.common.script.builtin.DatasetUtilities$PyDataSet indices must be integers
... 62 common frames omitted