A way of collecting notes searching all attributes

Thanks - I thought so but wanted to be sure. In my case when starting with TB three or four weeks ago I created many notes changing the attribute names to store the same information type fairly frequently. This was my TB discovery phase. This means I have notes with say the text “Soil Moisture” connected to user attributes such as $MyText, $Product, $Application etc…I’m cleaning up now assigning all notes with information on soil moisture the attribute $SatelliteProduct == “Soil Moisture”.

I’m using the global find provided by the TB environment. I only have 40-5o notes and perhaps 5 attributes to clean-up into one so the manual clean-up is ok. For several 1000s it would be more onerous.

Perhaps at a tangent, but a good strategy is to put things you want to search for in a discrete attribute. If you need clear sub-groups within your overall ‘tags’ (keywords), use discrete attributes.

I find Tinderbox’s built-in search leaves a lot to be desired, but you can improve things by using an agent.

This TBX file (57.8 KB) has a top-level agent that will search for notes that contain all of the words in its $Name. (Note that unlike in the built-in search, the words can appear in any order and need not be next to one another, or even in the same attribute.) You can specify which attributes the agent searches by setting the agent’s SearchAttributes key attribute. This search is potentially quite costly, since it will be common to search through the $Text of notes, so if the agent has no words in its name, it deactivates itself, and reactivates itself when a word is entered into its name.

I usually have one of these at the root level of my documents ready to go if the built-in search doesn’t get the job done.

This still doesn’t do what you’re really looking for, in terms of searching every attribute. But it’s easy to add a large set of attributes to search, which is not possible in the built-in search.

2 Likes

A brilliant answer from Galen - many thanks. I’m using the occasion to learn a little more about actions in TB. I understood the edict (which switches the agent on and off depending if there is a name or not). The code for the actual search is a little more mysterious.

eval($SearchAttributes(agent)).icontains($MyRegex(agent)); 

the left hand side is a concatenated string with the attribute values in each note to be searched, correct ? I assume that $MyRegex(agent) is then a list of search terms but I’m not sure what it looks like in practice. Can you give an example or explain a little more the mechanics ?

Thanks - in fact there are some useful TB idioms in you’re answer. In particular the distinction between attributes that carry information ($MyRegex as an example) for the computation and attributes that execute code ($AgentQuery).

In this case the answer I was looking for is plainly visible under $MyRegex.

Yes. In the context of the query, $SearchAttributes(agent) refers to the agent’s $SearchAttributes attribute (set to the string "$Name + $Text + $MyString" in the example document). When this string is evaled, it is evaluated in the context of the note the agent is examining, so the $Name, $Text, and $MyString of the note the agent is examining are concatenated together. This is then searched to see if it matches $MyRegex(agent).

$MyRegex is set by the agent’s $Edict. The edict uses the string .replace operator to put each word in the agent’s $Name into a non-consuming-match expression. (In the example document, the agent’s name of “foo bar” yields the $MyRegex (?=.*foo)(?=.*bar). Briefly this regular expression looks for “foo” anywhere in a string without consuming any of the string. It then looks for “bar” anywhere in the string without consuming any of the string.) The result is a regular expression that will match when every word present in $Name is present in the search string.

thanks for reminding me of the eval statement, was trying to remember that.

I feel if I can teach myself how this works, the scales will fall from my eyes and my use fo Tinderbox will become MUCH richer… But at present I don’t quite understand how I would construct something like this in my own document. Am trying!

You might not need to construct something like this!

The simplest, most common case, is of course an agent that looks for something in one attribute:

$Text.contains("Plessy")

$Name.contains("Plessy")

Often, you might want to look in two or three places:

$Text.contains("Plessy") | $Name.contains("Plessy")

The original question was, "can I search for “Plessy” anywhere? Tinderbox doesn’t do this because that would be slow: a Tinderbox note has something like 500 attributes. It’s not very likely that Plessy would be found in $BorderColor or $Phone, but it’s not impossible.. And then, when you find that there’s a “Plessy” in some attribute of a note named “James Arbuthnot”, how would you figure out in which attribute it was found?

If you could tell us a bit more about what you’re working on, I bet we could find some helpful ideas!

If you are looking for a word I agree that you probably have an idea in which attribute it might be located. The problem I face sometimes is when I export and then re-import a spreadsheet into TB. Perhaps I changed a couple lines in the sheet which are now notes in TB but can remember which ones.

Ideally I would like to locate those notes which are identical to each other and eliminate the duplicates. Identical in this case means the same attributes (including text). There is no way to my knowledge of asking TB whether this note is identical to the other. Only on an attribute but attribute basis.

But of course not all of the attributes are in fact identical. For example:

• If the notes were imported into different containers, they’d have different values for $Container.

• The notes will have different values for intrinsic attributes like $ID, $Xpos, $Ypos, $Created and $Modified.

I do have some ideas for approaches to this problem.

I share the the same mystification. “Garbage-in-garbage out” or “where’s the piece of paper?”. This is why process-led things like Roam, or zettelkasten confuse me. Tipping all my cr*p, into the hopper of a fixed process doesn’t, of itself, really help with making sense of it. Also, it seems natural that the app should just know, but as has been noted above that means many places we likely don’t want/need to look.

Unless I embrace metadata likely all my ‘words’ are marooned in $Text or $Name which are easy to find. If I use ‘tags’ (aka keywords), $Tags might be of note. Beyond that the ‘words’ are in a user attribute to which I ascribed it.

The point being, I think the premise here is flawed. At loosest I might want to search every one of a list of user set attributes for a value. But this begs the question, if I don’t know where I put the data in the first place, should I not solve this upstream.

This isn’t critique but a reminder of enlightened self-interest. IME, with Tinderbox, the sooner i place critical words or group-labels, into user attributes, the more useful the app becomes. Every time, in my own work, I find myself testing $Name/$Text, I think I’ve failed. Metadata FTW!

On the other hand, I can imagine wanting to have a query that asked:

• Are the user attributes for these two notes identical?
• Are the Displayed Attributes for these two notes identical?
• Given a list of attributes, are the attributes on that list identical?

Relevantly, is an agent—that by default searches at doc scope—the context to compare only two item?

Hits the nail on the head. For instance if the user attributes for one of the notes is not identical to the other one then it might be a good idea to make them identical in some cases or perhaps they are duplicates and the $Text elements should be merged. I have notes in a container sometimes which - since they below to the same project, are written by the same person etc… will often (not aways or I’d use a rule) should have the same user attributes. Writing them down quickly e.g. during a meeting I don’t always have the time to fill out all relevant attributes. I can quickly adjust later it if I have a mechanism to check the equality of a note with say a reference note with all field filled out properly.

1 Like

I don’t have a real plan for this yet, but I need practical projects to understand how stuff works.

Practically speaking, I would only likely be searching $text and $name, as suggested above. I think it would be useful to have search agents that can look for thinks like:

  • Names, when I inconsistently spell them (Christopher Hatty v. Christopher R. Hatty)
  • Words I frequently misspell by transposing characters (reciept/receipt)
    Maybe impossible, or may already exist, but I’d learn from trying!

Hi Christopher, you may find this video helpful. It explains how to search attributes and pull the data out to find misspellings.

Tinderbox attribute names are case-sensitive ($Name and $Text). Without wishing to appear pedantic, I’m aware we are all used to different conventions so what might be casual typic might easily be an echo of conventions in some other app. :slight_smile:

I use TextExpander. I’m a left-handed, dyslexic, two-finger typist. I’ve stopped worrying and just add my commonest typing errors to TextExpander and my cr*p typing is (mostly :frowning: ) hidden from the world.

Detect these errors is best done in input, AI cleverness is unimpressive. Apple apps constantly flag there, they’re as potential errors when they are—to any literate English native speaker—correct. Computers can’t yet truly understand the range of human writing.

1 Like

Thanks Mark. I wasn’t aware of the case-sensitivity. Nothing wrong with pedantry in a learning forum! I hadn’t thought of using Typinator to fix my errors on the front end. Good idea!

1 Like

Great. Given your last you may find this article useful. :slight_smile: