# Tag binding or expression to read dynamic list of tags

**URL:** <https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610>\
**Category:** Ignition\
**Tags:** ignition81, perspective\
**Created:** [July 19, 2023, 8:12pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610 "2023-07-19T20:12:21Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kevin\_Ar](https://avatars.discourse-cdn.com/v4/letter/k/b4bc9f/32.png) [@Kevin\_Ar](https://forum.inductiveautomation.com/u/Kevin_Ar)\
**Post date:** [July 19, 2023, 8:12pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/1 "2023-07-19T20:12:21Z")

</div>

I have a perspective view with a custom prop that holds a list of status tags. This list is generated dynamically so it might say [tagpath1,tagpath2, tagpath3] or [tagpath4, tagpath5] or [tagpath6] so the size of the list changes. I want to read all the tags and do an AND to get the overall status, what is the best way to achieve this?

A tag binding only takes a single tagpath from what I've seen, so what is the best way to do this?

1. An expression binding using tag()? This works if the number of tags in the custom prop are the same but I could get anywhere from 2-5 tags depending on the area. I can't find a way to loop within an expression.
2. A runScript expression binding that calls system.tag.readBlocking to read the tags then combines the values. My understanding is that a tag binding or expression will update immediately but the runScript will only update at the pollRate so this option results in slower updates.
3. Configure a tag binding that can read all the tags??

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [July 19, 2023, 8:17pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/2 "2023-07-19T20:17:29Z")

</div>

This isn't possible in a pure expression without @pturmel's simulation Aids module.

You can do it in script, so runScript expression or a propertyChange event that calls a library function will work.

```auto
def getStatus(paths):
    #assume that all paths point to boolean values
    return all(qv.value for qv in system.tag.readBlocking(paths))

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 19, 2023, 8:20pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/3 "2023-07-19T20:20:29Z")

</div>

> [@lrose](#):
>
> This isn't possible in a pure expression without @pturmel's simulation Aids module.

Not even **with** my SimAids module. The `tag()` expression function is not compatible with my iterator functions, as best I can tell.

---

<div class="post-metadata">

**Author:** ![Kevin\_Ar](https://avatars.discourse-cdn.com/v4/letter/k/b4bc9f/32.png) [@Kevin\_Ar](https://forum.inductiveautomation.com/u/Kevin_Ar)\
**Post date:** [July 19, 2023, 8:31pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/4 "2023-07-19T20:31:22Z")

</div>

Thanks for the quick help!

I started with the runScript method then wanted to see if there was a better way as I know runScript is to be avoided if possible. Guess i'll stick with it.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 19, 2023, 9:09pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/5 "2023-07-19T21:09:28Z")

</div>

Can you use an expression structure binding preconfigured to read all the tags, and then extract by key/index the ones you 'care' about?

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [July 20, 2023, 12:40am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/6 "2023-07-20T00:40:49Z")

</div>

I would think that the penalty of using runScript compared to a script transform would be the same (interested to know though), but the benefit of a script transform is legibility, so I would use that

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 20, 2023, 12:42am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/7 "2023-07-20T00:42:57Z")

</div>

I'd expect a script transform to do slightly better than `runScript`, actually, but would also be interested in benchmarking. One of these days...

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [July 20, 2023, 12:45am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/8 "2023-07-20T00:45:45Z")

</div>

Speaking of benchmarking, it would be **great** to have a complete\* list of benchmarking results comparing different ways of doing things to reference. I think that'd be super beneficial from a design and end user perspective to maximise performance

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 20, 2023, 12:49am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/9 "2023-07-20T00:49:07Z")

</div>

> [@paul-griffith](#):
>
> I'd expect a script transform to do slightly better

Because?

(The difference does happen to be non-benchmarkable with my new tools...)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 20, 2023, 12:53am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/10 "2023-07-20T00:53:26Z")

</div>

Script transforms have a more direct optimization story; there's (modern) effort to ensure that they don't have to perform the Jython interpretation/compilation step, where `runScript` relies on a string equality check every time `execute()` is called.  
_If_ the de-duplication logic ends up being identical, they should indeed end up basically the same. The difference would only be if one or the other ends up "compiling" the code too often.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 20, 2023, 12:54am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/11 "2023-07-20T00:54:23Z")

</div>

> [@pturmel](#):
>
> non-benchmarkable with my new tools

Just had an idea--hold the line for a few minutes....

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [July 20, 2023, 12:59am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/12 "2023-07-20T00:59:28Z")

</div>

> [@pturmel](#):
>
> hold the line

I don't know about the line, but I'll hold your beer

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 20, 2023, 1:54am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/13 "2023-07-20T01:54:14Z")

</div>

See my fresh post over here:

> [@Automation Professionals' Integration Toolkit Module](https://forum.inductiveautomation.com/t/automation-professionals-simulation-aids-v2/74934/42):
>
> I had some dead time today. Party! Anyways, several new functions: alias() wraps a dataset with a string prefix for each column name nanoTime() just calls java's System.nanoTime() and returns the timestamp. crossJoin() does what you'd think with two datasets. innerJoin() takes two datasets, plus pairs of iterator expressions to match up. leftJoin() as for innerJoin(), but includes a null right row if a row on the left has no match on the right. For Ignition v8.1+: v2.0.6.232…

As for the benchmarking, I just played with my new `nanoTime()` in some simplistic scenarios aimed at measuring overhead, returning delta nanoseconds as the output value.

The simplest is an expression like so:

```auto
runScript('transforms.deltaNanoTime', 2000, nanoTime())

```

where the `transforms` script module includes this:

```auto
def deltaNanoTime(ts):
	return System.nanoTime() - ts

```

The above reports consistently (after first execution) in 40 - 50 **micro** seconds. I'm not sure if my `nanoTime()` function is being executed in the call chain before runScript sets up (part of) the script environment.

The next simplest is this, with a squirrely use of my `asList()` function to make it re-execute every couple seconds:

```auto
asList(
	now(2000),
	objectScript('transforms.System.nanoTime() - args[0]', nanoTime())
)[1]

```

This runs consistently in 180 - 200 **micro** seconds. The call to execute subexpressions is before any script environment setup.

The next three scenarios aim to measure transform overhead. Each of the following has an initial expression that looks like this:

```auto
asList(
	now(2000),
	nanoTime()
)[1]

```

The output of this first stage is the `nanoTime()` value, and retriggers every two seconds. The time between execution of `nanoTime()` and delivery to the next stage is tiny.

The above is fed to this **script transform** :

```auto
def transform(self, value, quality, timestamp):
	return transforms.System.nanoTime() - value

```

This is pretty noisy, with values anywhere from 300 to 900 microseconds, but mostly around 550 - 600.

The first stage is then fed (separate binding) to this **expression transform** :

```auto
runScript('transforms.deltaNanoTime', 0, {value})

```

This is also noisy, with values from 250 - 900 microseconds, but mostly around 500. Just a bit faster than a very similar script transform.

Finally, that first stage is fed to this **expression transform** :

```auto
objectScript('transforms.System.nanoTime() - args[0]', {value})

```

Noisy, again, but a bit less. From 300 - 450. Just a bit faster than `runScript()`, by eye.

Probably ought to collect some stats with `recorder()`.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 20, 2023, 1:55am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/14 "2023-07-20T01:55:49Z")

</div>

Summary: transforms are terrible.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 20, 2023, 3:03am UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/15 "2023-07-20T03:03:26Z")

</div>

Interesting. It suggests there's a significant bottleneck in a common layer, which also suggests there might be room for improvement. I'll have to make a note to skim that code at some point.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 20, 2023, 12:51pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/16 "2023-07-20T12:51:51Z")

</div>

Collected some overhead stats. Added a sixth binding for comparison, and made them all trigger from a common reference. The new expression transform looks like this:

```auto
nanoTime() - {value}

```

It is notably faster than the other transforms.  
To make the `recorder()` run smoothly, I made a trigger timestamp with `now({this.custom.pace})` and set pace to 200. Then I modified the transforms' first stages to look like this:

```auto
asList(
	{this.custom.trigger},
	nanoTime()
)[1]

```

The non-transform tests of `runScript()` and `objectScript()` now use that structure, too.

Results ('RS' is runScript, 'OS' is objectScript):

 ![20230720_084044-Transform Timing Stats](https://us1.discourse-cdn.com/inductiveautomation/original/3X/4/6/46513fdd95e51623803bffa2469468bf20b313aa.png)

The bare `runScript()` result is so low that I'm not sure I believe it, as the difference between `runScript()` and `objectScript()` is much less in the transform setup.

Anyways, avoid transforms, and if you can, avoid scripts entirely.

Do notice how much faster everything runs without the designer, and how it skewed my observations last night.

---

<div class="post-metadata">

**Author:** ![justin.brzozoski](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justin.brzozoski/32/13452_2.png) [@justin.brzozoski](https://forum.inductiveautomation.com/u/justin.brzozoski)\
**Post date:** [July 20, 2023, 4:10pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/17 "2023-07-20T16:10:33Z")

</div>

I'm definitely interested in the deep dive into transform overhead, but to circle back to OP's question, our project is plagued with dynamic lists of tag paths in every view, so we've tried all sorts of things.

In cases when the max number of tags is not too high we will sometimes use an array of normal indirect tag bindings sized to our max possible number, and just use a path to an unchanging dummy/default memory tag in all the slots we don't need. It's annoying to setup all the tag bindings the first time, but works fine after that.

Honestly, our project would be so much simpler if there was a method to have a property take in an array of tag paths and spit out an array of tag values, and have the individual tag values in the array update in a dynamic (non-polling) manner.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 20, 2023, 4:55pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/18 "2023-07-20T16:55:27Z")

</div>

> [@justin.brzozoski](#):
>
> if there was a method

Maybe abuse a hidden table with a column view defined that has the indirect binding you need, and message tag values from that nested view to page scope where the table could listen for them... Include a UUID perhaps, to make sure the messages are handled by the correct target.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 20, 2023, 4:57pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/19 "2023-07-20T16:57:16Z")

</div>

> [@justin.brzozoski](#):
>
> Honestly, our project would be so much simpler if there was a method to have a property take in an array of tag paths and spit out an array of tag values, and have the individual tag values in the array update in a dynamic (non-polling) manner.

So, a new binding type that accepts an input property but knows to "spread" it as a list and read all the inner paths?  
That'd be tricky to explain to users but easy to implement...

---

<div class="post-metadata">

**Author:** ![justin.brzozoski](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justin.brzozoski/32/13452_2.png) [@justin.brzozoski](https://forum.inductiveautomation.com/u/justin.brzozoski)\
**Post date:** [July 20, 2023, 5:34pm UTC](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610/20 "2023-07-20T17:34:32Z")

</div>

> [@paul-griffith](#):
>
> So, a new binding type that accepts an input property but knows to "spread" it as a list and read all the inner paths?  
> That'd be tricky to explain to users but easy to implement...

Yeah. The explanation feels simple to me: it behaves identically to an indirect tag binding, except if the input parameter is an array, then the output is an array.

I imagine it would look like this in use, with "tag\_values" using the whole of "tag\_paths" as the only parameter to it's binding:

![property_sample](https://us1.discourse-cdn.com/inductiveautomation/original/3X/2/c/2ce63da7dfd770617ede1ecd495800ab78a0d551.png)

[Next page](https://forum.inductiveautomation.com/t/tag-binding-or-expression-to-read-dynamic-list-of-tags/76610.md?page=2)
