Tinderbox Forum

Feeding an array of parameters to a query

Is there a simple way to feed an array to a query?

I’ve built this Query:

$Name=="Trm- Authentication"|$Name=="Trm- Identification"|$Name=="Trm- Identity"|$Name=="Trm- Personal Data"|$Name=="Trm- Personally Identifiable Information"

What I’d like to know is if there would be a way to do something like this?
$Name=="Trm- Authentication"|"Trm- Identification"|"Trm- Personal Data"|"Trm- Personally Identifiable Information"

In other words, I don’t want to have to keep repeating the $Name call.

I have a solution. This stamp pulls the values from $Term and generates the $AgentQuery. I have to so the .substr operator because a query fails if there is a following “|”.

$AgentQuery="";
$Term.each(x){
$AgentQuery+='$Name=="Trm- '+x+'"|';
};
$AgentQuery=$AgentQuery.substr(0,-1);

I’m just wondering if there is a more elegant way of doing this.

Later, I’ll do a post to show what I’m up too. It is wickedly cool!

I asked what I think is a similar question a while back and @eastgate Mark provided a solution:

My request was to avoid repeating $Prototype==, and he suggested

  1. Make a note – say a top-level note named InterestingPrototypes.
  2. Set $MySet of InterestingPrototypes to the list of your interesting prototypes — perhaps “Task;Project;MaybeSomeday”
  3. In your agent, the query becomes
     $MySet(/InterestingPrototypes).contains($Prototype

Does that help?

1 Like

Ok, this works, but I’m not exactly sure why (I think the answer is we’re just reversing logic; which is very cool!)

I have $MySet(agent).contains($Name) where $MySet in the agent contains the names I want to search on. @eastgate can you explain/confirm what is happening, in English?

I thought queries read something like…$Name.icontians("term)… would mean find all notes whose name contains the “term”. But what is the above seems to be saying is “Find all notes whose $Name appears in the agent’s $MySet” Are we just reversing the logic? Seems to work.

But, I’m forced to ask, why is that a problem? You write the code and never look at it again. Spending N times as long as it took to write the original on worrying if there is a shorter version seems a poor trade.

You want ‘attribute value exactly matches a single list value’. Tinderbox doesn’t have such an operator. But, we can reverse the context:

As documented, in a multi-value data type—like a Set or List, the == operator only matches whole discrete values within the overall list. So, what this does is test if any single value of the agent’s $MySet is the exact equivalent of the tested $Name.

Sometimes you get to do things the way you find intuitive, sometimes you don’t. :slight_smile:

I don’t know how it works either!

I suppose it could be:

  1. All Queries are really just boolean tests saying “include a note if and only if the $AgentQuery returns true.

  2. If a note’s $Name is in $MySet(agent), then the expression evaluates to true and so the note is included.

That’s my guess, anyway…

Say you’re using a query as a repeatable mechanism for changing various attributes for a changing range of prototypes: the exact list of prototypes varies each time, but usually contains several entries. It’s much easier to change the set of prototypes in an attribute than it is to hack multiple $Prototype== statements each time.

That seems a reasonable tradeoff, much as it makes sense to use a $SearchTerm attribute with a query $SearchTerm(agent) to facilitate repeatable queries.

1 Like

Well, have you tried .intersect()? That tells you if any items in list A are also in list B. Here one of the lists could be a single value list (a string!). Although the result is note path(s), if you gat a result other than `""~ you have a match. Having got a free moment to try some code using .intersect(), it turns out it doesn’t work in this agent context (but works fine in more normal use).

Plus, if you are hard-coding lists, you’re not availing yourself of available action code. For instance, your changeable list could be formatted into a query string then accessible as an attribute value (check out .format()). Functions probably make it easier to do that. I’ll leave that as an exercise.

Many action operators simply make easier a task one might code oneself. Thus the recommendations seen in the forum that if the ‘problem’ is significant enough, make a feature request. Anyone can do so, but it is best done by the person with the problem. As I know for doing just that over the years, sometimes a new operator arrives (or sits on the spike as a possibility) or it turns out there is already a solution.

To dive deeper, it might be useful if you could offer up a TBX showing the problem with a set of instructions as to how to see the problem and as importantly the desired outcome. My sense this is a case of revisiting some dogmatic assumptions about how a process should occur, but I’m ready to see a doc proving the opposite.

HTH.

I think we’re talking at cross purposes here…

My original request (months ago) was how to avoid having to type out complicated queries of the form $Prototype==A|$Prototype==B|...|$Prototype==H, where a certain attribute is repeated several times, which is tedious and prone to error, especially if you know that at some point that you’re going to want to change the content of the query.

Other languages provide something along the lines of in {x,y,z} and I wondered if there was an equivalent.

Mark B responded with the suggestion to use the syntax I repeated above ($MySet(agent).contains($Prototype)).

That works perfectly for what I wanted, so I’m not sure why you think I’m looking for additional features. I’m not. It seemed to fit Michael’s request, so I passed it on.

Of course I could fill $MySet(agent) with action code if I wanted, but that’s a side issue: the point was avoid the manipulation of long queries on the same attribute in favour of a simpler approach, and Mark’s solution does that admirably.

No need for any feature request – or are you seeing something I’m missing?

Crossed lines, indeed due to concurrent posts. My previous reply (that you quoted) was to someone else!

I know! You asked why one would want to simplify a complicated query, and I gave you a couple of examples.

Mark B’s solution works admirably for that (and I think for Michael’s original question) so I was curious what additional feature you thought ought to be requested, that’s all.

1 Like

BTW, you may have notes my intuited solution with .instersect() doesn’t work (I amended the relevant post so as not to mislead later readers). A shame, as if usable in a query it could do what you want.

Otherwise, I would have suggested the solution MB already gave. Indeed, use of .contains() is documented here as the method to use when you want to do a == equality check against multiple values. A caveat is that for lists you can only match full values and can not do regex partial matches.

†. Yes, there is a workaround for that caveat, but its a digression here: see here if interested in the workaround.

1 Like

[Set].contains(anElement) returns true if one of the members of the set is equal to anElement. So, if $MySet is Bilbo; Frodo; Gaffer Gamgee; Sam Gamgee; Meriadoc; Pippin, $MySet.contains($Name) will be true of the note’s name is a “Frodo” but false if the note’s name is “Gimli”.

1 Like

Professional programmers often spend their time trying to work out such things — they know that the likelihood of not having to look at it again is usually a pipe dream. They also know that understandability is paramount above all else (it saves time in the long run). And economy of expression is valued as writing less code leads to fewer errors, enhances understandability, and generally saves time. Becoming good at programming (which writing action code is an example of) requires learning these lessons.

4 Likes

BTW, this works great when you want to extend it to search on other parameters, e.g. not just a company name but also a prototype:

$qOrg(agent).icontains($Organization)&$Prototype=="pGap" returns the notes that have the value of the companies listed in qOrg of the agent and are assigned the prototype Gap.

Very nice and tight. Love it.

Just figured out, however, that this approach will NOT work when running queries on Attribute Browser.

Being able to add attributes to the query on attribute browser could be a nice addition in the future.

Although, this works great:
image

You can call the $MySet from the agent. :slight_smile:

The attribute browser does not bind the designator agent: only agents do that. The underlying technique will be fine: you simply need to identify where you’re storing the set/

2 Likes