Find in all fields and list the tiddlers that contain the value

Hello everyone,

I am trying to list all tiddlers where the current tiddler’s title is listed in any of their fields.

Let’s say the current tiddler is DouglasAdams so for example this filter [field:author[DouglasAdams]] returns any tiddler that has DouglesAdams in the author field, but I would like to list all tiddlers that have DouglasAdams in any field, whether the field is “author” or “source” or “bigbrains” or anything else. Seems like such a simple thing but i just can’t seem to find/figure out an answer :sweat_smile:

The obvious answer to me is to leave the field empty like [field[]has[DouglasAdams]] but that gives me no results. or [fields[]match[DouglasAdams]] but that also gives me no results, the same with field instead of fields does, but it just returns the tiddler that has that title.
I searched on tiddlywiki.org, talk.tiddlywiki, even looked at regular expressions but I can’t choose the field with a regular expression. I feel stuck, I apologize if this is super basic.

ok, this seems to be doing the trick!

[all[tiddlers]search:*[DouglasAdams]]

Have a closer look at: https://tiddlywiki.com/#search%20Operator

Edit: It seems you found it yourself. So my link is for others that find this thread :slight_smile:

1 Like

If you are just doing a simple search, you can try this plugin $:/plugins/kookma/search. It is very convenient.

1 Like

Note that this will only work correctly if the values you are searching for do not contain spaces. For example, suppose you want to find “Douglas Adams” (with a space), and you have two tiddlers, one with “Douglas Adams”, and another with “[[James Adams]] [[Douglas Trumbull]]”. If you search using

{{{ [all[tiddlers]search:*[Douglas Adams]] }}}

It will find THREE tiddlers. This is because the search:*[] filter operator separately matches keywords “Douglas” and “Adams”, but doesn’t recognize the doubled square bracket “list” syntax. It also matches the tiddler in which your search filter syntax occurs. You can account for this by using:

{{{ [all[tiddlers]search:*:literal[Douglas Adams]] -[<currentTiddler>] }}}

which finds fields containing an exact match to the parameter value and ignores the tiddler in which the search filter syntax occurs.

Alternatively, you could use a regexp pattern, like this:

{{{ [all[tiddlers]search:*:regexp[Douglas\s*Adams]] -[<currentTiddler>] }}}

which will match “DouglasAdams” or “Douglas Adams” or even “[[Douglas Adams]]” … but NOT “[[James Adams]] [[Douglas Trumbull]]”.

Of course, this means that you need to have the “\s*” pattern in your search string. But if you are getting the search string from user input (i.e., via an $edit-text widget), you will probably want to just type “Douglas Adams” (with a regular space character).

Fortunately, this can be handled with a little “fixup” code to replace the spaces with \s*. Something like this:

<$edit-text field=find/>
<$let pattern={{{ [{!!find}search-replace:g[ ],[\s*]] }}}>
<%if [<pattern>!match[]] %>

{{{ [all[tiddlers]search:*:regexp<pattern>] -[<currentTiddler>] }}}
<%endif%>

Notes:

  • The <%if%>...<%endif%> conditional syntax prevents the search from finding ALL tiddlers when no input has been entered into the $edit-text widget.
  • While the search filter syntax doesn’t contain the literal text you are searching for, the currentTiddler still has a field named find that contains that input text, so you still need !match<currentTiddler> to prevents the search from finding that tiddler.

enjoy,
-e

4 Likes

Great!

Can you foresee a efficient(-ish) way to have the result list clarify which field contains the search term?

I did manage a version, but I suspect you’d be more efficient!

<$list filter="[all[tiddlers]search:*:regexp<pattern>] -[<currentTiddler>]" variable="tiddlerContaining">

<$tiddler tiddler=<<tiddlerContaining>> ><$link/>

— <$list filter="[<currentTiddler>fields[]]" variable="candidateField"><$text text={{{ [<currentTiddler>get<candidateField>] :filter[search::regexp<pattern>] :then[<candidateField>] }}}/>
</$list>

</$tiddler>
</$list>

And for the sake of the thread, here’s a live demo of search all fields and SHOW which field has the search string — a bit enhanced since posting the code above.

I suspect it may not be any more performant, but if you’re looking for more efficiency from a code standpoint, you could combine the filter step into the parent list:

<$list filter="[<currentTiddler>fields[]]
		:filter[<..currentTiddler>get{!!title}search:title:regexp<pattern>]">
	<$text text={{!!title}} />
</$list>
  • Note that within a :filter run, {!!title}/<currentTiddler> refers to each output of the previous filter run, and <..currentTiddler> refers to the value of <<currentTiddler>> outside the filter.

I use this type of filter occasionally, and like to use the fields:exclude suffix to improve the performance a bit.

<$list filter="[<currentTiddler>fields:exclude[title type created creator modified modifier]]
		:filter[<..currentTiddler>get{!!title}search:title:regexp<pattern>]">
	<$text text={{!!title}} />
</$list>

And if you habitually find yourself wanting to exclude the same set of fields (perhaps system fields?) from a filter, you can also define a global variable by putting the definition in a tiddler with the tag $:/tags/Global or $:/tags/Macro, e.g.

\define excludeFields() title type created creator modified modifier

and use it like this:

<$list filter="[<currentTiddler>fields:exclude<excludeFields>]
		:filter[<..currentTiddler>get{!!title}search:title:regexp<pattern>]">
	<$text text={{!!title}} />
</$list>

Even if you don’t need a global <<excludeFields>>, I find it easier to add or remove field names from a definition at the top of a tiddler than “in place” in the fields parameter.

1 Like