Shortcut to search Draft by partial or multiple tags

Many of my Drafts are messages that are tagged with the person’s name the Draft is send to and the topic of the message, e.g. firstname-lastname and topic.

My goal is to create a shortcut (particularly for iOS) that

  1. takes one or multiple tags as input
  2. returns a list of all Drafts that contain all of the tags, e.g. the name and the topic, where both exact matches and partial matches are allowed
  3. lets me choose one of the matching Drafts
  4. opens the chosen Draft in the Drafts app

Below is a screenshot of my current solution. Problems are:

  • The shortcut only works for a single tag, e.g. either the name or the topic
  • The shortcut only works for exact matches and not for partial matches. When I give firstname as an input, I would like to find all Drafts tagged with firstname-lastname.

Appreciate any ideas, thanks!

More Advanced Searches

Try ignoring the tags field in the “Search Drafts for” step, and just using the search text (showing “updated text” in your screenshot above). In particular look at the advanced query syntax you can use, it works in that field from Shortcuts (I just double checked it still does), and will give you a lot more control over how you search.

Tag Matching

I think that you should be reviewing your tag utilisation for that. Rather than “john-smith”, you could have two tags “john” and “smith”, or nested tags “john/smith”.

Re-tagging Options

With these, you could enter either just “john” in the case of fragmenting your tags, or “john/” in the case of nexting your tags.

For the first case, searching for “john” would find you someone who was named “John Smith”, and also find him with a search for “smith”. But, sometimes forenames are also valid surnames (“Neil”, “Morgan”, “Ryan”, etc.), so that might be something to consider.

For the second case, you would in effect have the forename as the root level tag, so searching for “john/” would only match fornames and not surnames (as they would be nested one level below the root). But, you would not be able to search for the last name “smith” without including the root/forname.

To search by full name, you would simply search for both tags in the first case (with AND logic), and in the second, you would search for the full nested tag - “john/smith”.

Each approach has that divergence on what is in and out based on the surname level, so it would simply be a preference to choose one, plus whatever other factors you might implement in management of your tags.

Partial Matching Tags

If you really had to do it without modifying your approach to tagging, then I would look at retrieving all tags from Drafts (you could use an action to compile them and return them to Shortcuts via the “Run action with text” step for Drafts in Shortcuts), looping through them to identify your partial matches (should “John” match to “Johnny Smith” for example?), and then putting those quries into your query string.

Evaluation

I would recommend the approach of revising your tagging system against trying to create partial matches against tags. Tags are there to help with categorisation for retrieval, but the set up looks to be hindering you (the proof is if you try to do this just in Draft’s built-in search functionality). Such hinderances are usually a sign that a modification to your tagging system is due, but I don’t know what other factors you might have to consider. Perhaps you have a common tagging approach across a half dozen systems, so the impact of changing it would be further reaching.

Ultimately, go with the most flexible and least friction approach you can get away with.

 
I hope that helps.

1 Like

@sylumer I will carefully review your advice later.

Just want you to know that it is so awesome and incredibly appreciated that you take the time (over and over again) to write all of that out in order to help me and others on this forum!

Btw this exact problem is solved flawlessly on MacOS by a Python script, which - of course - is only slightly modified from your amazing Doctor Drafts Alfred Workflow :sweat_smile:

Here’s my solution for anyone coming across this thread in the future. I kept my kebab case tagging strategy, but implemented pretty much exactly what @sylumer suggested apart from that.

The shortcut works with multiple and partial tags as long as each partial tag is uniquely identified.

Note: That last restriction can be easily circumvented but works fine for my needs. It comes from exiting the loop over all existing tags after the first match in the Drafts Find First Matching Tag shortcut below. Instead, one could loop until the last match is found and return an array of all matches.

The shortcut is constructed in 4 steps:

  1. A Drafts action Copy all Tags to Clipboard queries all existing Drafts tags across all Drafts and copied them to the clipboard.
  2. A helper shortcut Drafts Get all Tags runs the Drafts action of step 1 and passes the clipboard to the next action.
  3. A second helper shortcut Drafts Find First Matching Tag takes a single (partial) tag as input, iterates through the list of all tags, and returns the first full tag that contains the (partial) input tag.
  4. The main shortcut Drafts Search Draft by Tag finds the corresponding full tag for each partial tag, prefixes each full tag with tag:, searches for any Draft that contains all the full tags, prompts the user with a list of these Drafts and finally opens the selected Draft in the app.

I will append screenshots of the individual steps below. Note that the shortcuts are not entirely reproducible from the images since I like modularity and have extracted some actions into more helper shortcuts :innocent:
However, their implementation should be clear from the name and usually consists of just one or two actions. If there are questions left, feel free to ask them in this thread below!


Step 1:

Thanks to @sylumer who provided this code in a forum post and @agiletortoise for the improvement suggestions!

Update with improved code:

const uniqueTagsArray = Tag.query("");
const sortedTags = uniqueTagsArray.sort().join("\n");
app.setClipboard(sortedTags);

Original version:

const allDrafts = Draft.query("", "all", [], [], "modified", true, false);
const allTagCombinations = allDrafts.map((draft) => draft.tags);
// flattens array of combinations into array of individual tags
const allTagsArray = [].concat(...allTagCombinations);
const uniqueTagsArray = [...new Set(allTagsArray)];
const sortedTags = uniqueTagsArray.sort().join("\n");

app.setClipboard(sortedTags);

Step 2:

Step 3:

Step 4:

It’s not a great idea to load all drafts for anything. That could choke on a large dataset (it would probably run, but take a long time).

You can get all unique tags, or query for matching tags, with Tag.query docs much more efficiently.

Thanks for the suggestion, I will look into that and post the improved version below for later reference!

As suggested by @agiletortoise my original code can be simplified a lot since I am only interested in the unique tags:

const uniqueTagsArray = Tag.query("");
const sortedTags = uniqueTagsArray.sort().join("\n");
app.setClipboard(sortedTags);