Congratulations! If you’ve come this far and understand most from the previous lessons, you’ve nearly mastered Logseq queries.
In this lesson, we’ll take the pseudocode from the previous lesson and turn them into proper Logseq queries. As you’ll see, the syntax for Logseq queries is close to what we’ve written before.
But before we start applying our knowledge of Boolean logic, we first need to tell Logseq we want to run a query.
How to start a Logseq query
To tell Logseq you want to search using a query, you type /query
and hit the Enter key. This will give you the following macro:
{{query }}
If you’re familiar with programming, you can think of a macro as a function. Macros are also part of other data environments, like Microsoft Excel.
To keep things simple, remember this: a macro is a short computer script that enables you to record a series of actions.
Macros like queries enable us to automate our search operations. That’s why we write query code instead of clicking through a visual menu of filter options. By writing down the steps we want Logseq to take whenever we open a query, we can run it indefinitely without any further actions needed on our part.
Now that we know how to initiate a query, it’s time to use our knowledge of Boolean logic to tell Logseq what to search for.
Boolean operators = Logseq filters
The Boolean operators (AND, OR, NOT) from the previous lesson are called filters in Logseq. This is because we use them to filter the query results to show only what we’re looking for.
Apart from the basic boolean filters, there are more filters in Logseq: between, page, property, page-property, page-tags, task, priority, sort-by, among others. We’ll cover these filters in tomorrow’s lesson.
In this lesson, we’ll start easy by just using the three Boolean filters we already know.
The Boolean operators in Logseq
Let’s stay with yesterday’s Shakespeare theme.
If we wanted to find all branches that mention Shakespeare, Hamlet, Julius Caesar, and Macbeth, our pseudocode would look like this:
[[Shakespeare]] and [[Hamlet]] and [[Julius Caesar]] and [[Macbeth]]
(to see the full query, scroll to the right)
That’s a lot of ANDs! Luckily in Logseq, we just put the Boolean value at the start of a list of values (a sequence, get it?). Here’s what the pseudocode looks like in proper Logseq query syntax:
{{query (and [[Shakespeare]] [[Hamlet]] [[Julius Caesar]] [[Macbeth]]) }}
(to see the full query, scroll to the right)
As you can see, we wrap each list of search terms between parentheses. This tells Logseq what values belong together and in what order it should search for them.
This order of operations enables us to take the output of one query and use it as input for another query (the outer parentheses). This is what we ended with in yesterday’s lesson, and what we’ll end with in today’s lesson (see the next heading).
Like we did with the AND filter, we can use the OR and NOT filters similarly.
The query below looks for all the blocks that contain at least one of the links in the list:
{{query (or [[Shakespeare]] [[Hamlet]] [[Julius Caesar]] [[Macbeth]]) }}
(to see the full query, scroll to the right)
The query below looks for all the blocks that contain none of the links in the list:
{{query (not [[Shakespeare]] [[Hamlet]] [[Julius Caesar]] [[Macbeth]]) }}
(to see the full query, scroll to the right)
Now that we can work with the basic Boolean operators in Logseq, let’s combine them to fine-tune our search results.
Combining Logseq filters
By now, we’ve spent quite a bit of time with Boolean logic, so we’ll dive directly into the examples.
First, we want to see all blocks and branches that mention both Ghosts and Shakespeare:
{{query (and [[Ghosts]] [[Shakespeare]]) }}
But, we don’t want to see any blocks/branches that mention Hamlet:
{{query (and [[Ghosts]] [[Shakespeare]] (not [[Hamlet]])) }}
Here’s our first combined query! Can you see what steps Logseq takes?
First, this query grabs all blocks that do not contain the value [[Hamlet]]
. Next, it filters out any blocks or branches that do not contain the values [[Ghosts]]
and [[Shakespeare]]
.
Finally, we don’t want to see any blocks talking about Julius Caesar. The simplest way (without creating an additional order of operations) would be to write the query like this:
{{query (and [[Ghosts]] [[Shakespeare]] (not [[Hamlet]]) (not [[Julius Caesar]])) }}
(to see the full query, scroll to the right)
However, we can also create another level of nesting (order of operations). We can tell Logseq to first look for any blocks that contain the values [[Hamlet]]
or[[Julius Caesar]]
, filter those out, and then look for the values we do want to see. This is the resulting query:
{{query (and [[Ghosts]] [[Shakespeare]] (not (or [[Hamlet]] [[Julius Caesar]]))) }}
(to see the full query, scroll to the right)
With nested queries like the one above, it’s essential to keep track of the number of opened parentheses. A common bug is that a parenthesis is missing at the end of the query. So, always look first at the number of parentheses when a query is not working as expected.
Another common bug you might run into is that the query results are incomplete (not showing all of the expected results). This happens when Logseq has not yet indexed a newly created or changed block. You can force indexation by clicking on your graph name in the left sidebar and the Re-index option.
For today, this is probably enough new information to make your head spin. Tomorrow we’ll dive deep into what other filters we can use in Logseq.
Let’s finish with some practice!
Exercise
For each specification below, write the corresponding query. The list of values is already broken up for you, so you only need to place them in the correct order of operations. You can find the answers below the exercise.
Remember to keep track of the parentheses! One trick is to count the filters you’ve used and ensure you have as many closing parentheses in your query.
After you’ve finished the exercise, spend some time writing queries in your graph. Post your questions in this thread if you run into unexpected results.
- Search for all blocks that mention either Ghosts or Julius Caesar.
- Search for all blocks that mention both Ghosts and Shakespeare.
- Search for all blocks that mention Shakespeare but not Romeo and Juliet.
- Search for all blocks that mention Ghosts and Shakespeare but not Hamlet.
- Search for all blocks that mention Ghosts but not Shakespeare, Hamlet, Julius Caesar, or Macbeth.
Show answers
- Search for all blocks that mention either Ghosts or Julius Caesar:
{{query (or [[Ghosts]] [[Julius Caesar]]) }}
- Search for all blocks that mention both Ghosts and Shakespeare:
{{query (and [[Ghosts]] [[Shakespeare]]) }}
- Search for all blocks that mention Shakespeare but not Romeo and Juliet:
{{query (and [[Shakespeare]] (not [[Romeo and Juliet]])) }}
- Search for all blocks that mention Ghosts and Shakespeare but not Hamlet:
{{query (and [[Ghosts]] [[Shakespeare]] (not [[Hamlet]])) }}
- Search for all blocks that mention Ghosts but not Shakespeare, Hamlet, Julius Caesar, or Macbeth:
{{query (and [[Ghosts]] (not (or [[Shakespeare]] [[Hamlet]] [[Julius Caesar]] [[Macbeth]]))) }}