clean: Remove sources examples
This commit is contained in:
@@ -1,955 +0,0 @@
|
||||
---
|
||||
id: id-generated-by-omnivore
|
||||
title: Filters - Tasks User Guide - Obsidian Publish
|
||||
tags:
|
||||
- obsidian-tasks
|
||||
state: ARCHIVED
|
||||
date_published: 2021-05-25 01:00:00
|
||||
date_saved: 2023-07-16 10:23:46
|
||||
date_archived: 2023-07-16T10:05:15.231Z
|
||||
---
|
||||
|
||||
# Filters - Tasks User Guide - Obsidian Publish
|
||||
|
||||
#Omnivore
|
||||
|
||||
[Read on Omnivore](https://omnivore.app/)
|
||||
[Read Original](https://publish.obsidian.md/tasks/Queries/Filters)
|
||||
|
||||
## Webpage
|
||||
|
||||
## Filters
|
||||
|
||||
## Contents
|
||||
|
||||
This page is long. Here are some links to the main sections:
|
||||
|
||||
* [Custom Filters](https://publish.obsidian.md/tasks/Queries/Filters#Custom%20Filters)
|
||||
* [Searching for dates](https://publish.obsidian.md/tasks/Queries/Filters#Searching%20for%20dates)
|
||||
* [Text filters](https://publish.obsidian.md/tasks/Queries/Filters#Text%20filters)
|
||||
* [Matching multiple filters](https://publish.obsidian.md/tasks/Queries/Filters#Matching%20multiple%20filters)
|
||||
* [Filters for Task Statuses](https://publish.obsidian.md/tasks/Queries/Filters#Filters%20for%20Task%20Statuses)
|
||||
* [Filters for Dates in Tasks](https://publish.obsidian.md/tasks/Queries/Filters#Filters%20for%20Dates%20in%20Tasks)
|
||||
* [Filters for Other Task Properties](https://publish.obsidian.md/tasks/Queries/Filters#Filters%20for%20Other%20Task%20Properties)
|
||||
* [Filters for File Properties](https://publish.obsidian.md/tasks/Queries/Filters#Filters%20for%20File%20Properties)
|
||||
* [Appendix: Tasks 2.0.0 improvements to date filters](https://publish.obsidian.md/tasks/Queries/Filters#Appendix:%20Tasks%202.0.0%20improvements%20to%20date%20filters)
|
||||
|
||||
## Custom Filters
|
||||
|
||||
`filter by function` was introduced in Tasks 4.2.0.
|
||||
|
||||
Tasks provides many built-in filtering options, but sometimes they don't quite do what is wanted by all users.
|
||||
|
||||
Now Tasks has a powerful mechanism for you to create your own **custom filters**, offering incredible flexibility.
|
||||
|
||||
There are many examples of the custom filtering instruction `filter by function` in the documentation below, with explanations, for when the instructions built in to Tasks do not satisfy your preferences.
|
||||
|
||||
You can find out more about this very powerful facility in [Custom Filters](https://publish.obsidian.md/tasks/Scripting/Custom+Filters).
|
||||
|
||||
## Searching for dates
|
||||
|
||||
Tasks allows a lot of flexibility in the dates inside query blocks.
|
||||
|
||||
### Absolute dates
|
||||
|
||||
`<date>` filters can be given with 'absolute' dates, whose preferred format is `YYYY-MM-DD`.
|
||||
|
||||
Absolute dates specify a **particular date in a calendar**. They represent the same day, regardless of today's date.
|
||||
|
||||
Examples:
|
||||
|
||||
* `25th May 2023`
|
||||
* The [chrono](https://github.com/wanasit/chrono) library reads dates very flexibly, so you can use free text for absolute dates in your filters.
|
||||
* The `YYYY-MM-DD` format is somewhat safer, though, as there is no chance of ambiguity in reading your text.
|
||||
|
||||
### Relative dates
|
||||
|
||||
`<date>` filters can be given with `relative` dates.
|
||||
|
||||
Relative dates are **calculated from today's date**.
|
||||
|
||||
When the day changes, relative dates like `due today` are re-evaluated so that the list stays up-to-date (so long as your computer was not hibernating at midnight - see [#1289](https://github.com/obsidian-tasks-group/obsidian-tasks/issues/1289)).
|
||||
|
||||
Examples for inspiration:
|
||||
|
||||
* `yesterday`
|
||||
* `today`
|
||||
* `tomorrow`
|
||||
* `next monday`
|
||||
* `last friday`
|
||||
* `14 days ago`
|
||||
* `in two weeks`
|
||||
* `14 October` (the current year will be used)
|
||||
* `May` (1st May in the current year will be used)
|
||||
|
||||
Note that if it is Wednesday and you write `tuesday`, Tasks assumes you mean "yesterday", as that is the closest Tuesday. Use `next tuesday` instead if you mean "next tuesday".
|
||||
|
||||
### Searching date ranges
|
||||
|
||||
Date range searches were introduced in Tasks 2.0.0.
|
||||
|
||||
Tasks allows date searches to specify a pair of dates, `<date range>`.
|
||||
|
||||
These searches are inclusive: the dates at either end are found by the search.
|
||||
|
||||
#### Absolute date ranges
|
||||
|
||||
`<date range>` may be specified as 2 valid dates in `YYYY-MM-DD` format.
|
||||
|
||||
Dates on either end are included, that is, it is an inclusive search.
|
||||
|
||||
* `before <date range>` will match before the earliest date of the range.
|
||||
* `after <date range>` will match after the latest date of the range.
|
||||
|
||||
Notes:
|
||||
|
||||
* `in` and `on` may be omitted.
|
||||
* If one of the `YYYY-MM-DD` dates is invalid, then it is ignored and the filter will behave as `<date>` not `<date range>`.
|
||||
* Date range cannot be specified by 2 relative dates eg `next monday three weeks`.
|
||||
* It is technically possible to specify absolute dates in words, such as `25th May 2023`.
|
||||
* However, we do not recommend using words for specifying the two dates in ranges.
|
||||
* This is because we have found that using two adjacent non-numeric dates can lead to ambiguity and unintended results when the [chrono](https://github.com/wanasit/chrono) library parses the dates in your `<date range>` filter.
|
||||
|
||||
Example absolute date ranges:
|
||||
|
||||
Prior to Tasks 2.0.0, the second date in absolute date ranges was ignored. See the tables in the [Appendix below](https://publish.obsidian.md/tasks/Queries/Filters#Appendix:%20Tasks%202.0.0%20improvements%20to%20date%20filters) to understand the changes in results, and whether you need to update any of your searches.
|
||||
|
||||
#### Relative date ranges
|
||||
|
||||
Tasks supports a very specific set of relative `<date range>` values: `last|this|next week|month|quarter|year`. The pipe (`|`) character means 'or'.
|
||||
|
||||
Tasks will process these ranges, based on today's date, and convert them to absolute date ranges (`YYYY-MM-DD YYYY-MM-DD`) internally.
|
||||
|
||||
Dates on either end are included, that is, it is an inclusive search.
|
||||
|
||||
Notes:
|
||||
|
||||
* Currently all weeks are defined as [ISO 8601](https://en.wikipedia.org/wiki/ISO%5Fweek%5Fdate) weeks **starting on Monday** and **ending on Sunday**.
|
||||
* We will provide more flexibility in a future release.
|
||||
* We are tracking this in [issue #1751](https://github.com/obsidian-tasks-group/obsidian-tasks/issues/1751)
|
||||
* Relative date ranges support only the exact keywords specified above.
|
||||
* So, for example, `previous half of year` and `next semester` are not supported.
|
||||
|
||||
Example relative date ranges:
|
||||
|
||||
* `in this week` (from this week's Monday to Sunday inclusive)
|
||||
* `after this month`
|
||||
* `next quarter`
|
||||
* `before next year`
|
||||
|
||||
Prior to Tasks 2.0.0, the interpretation of relative date ranges was confusing, and not what most users naturally expected. See the tables in the [Appendix below](https://publish.obsidian.md/tasks/Queries/Filters#Appendix:%20Tasks%202.0.0%20improvements%20to%20date%20filters) to understand the changes in results, and whether you need to update any of your searches.
|
||||
|
||||
#### Numbered date ranges
|
||||
|
||||
There is also the ability to use numbered date ranges that are independent of the current date. These numbered date range types are supported:
|
||||
|
||||
* Week
|
||||
* Format: `YYYY-Www` (`ww` is the week number, always in 2 digits)
|
||||
* Example: `2022-W14`
|
||||
* Month
|
||||
* Format: `YYYY-mm` (`mm` is the month number, always in 2 digits)
|
||||
* Example: `2023-10`
|
||||
* Quarter
|
||||
* Format: `YYYY-Qq` (`q` is the quarter number, always 1 digit)
|
||||
* Example: `2021-Q4`
|
||||
* Year
|
||||
* Format: `YYYY`
|
||||
* Example: `2023`
|
||||
|
||||
Numbered date ranges were introduced in Tasks 3.1.0.
|
||||
|
||||
## Text filters
|
||||
|
||||
Filters that search for text strings have two flavours.
|
||||
|
||||
In the following examples, we describe the `heading` filter, but these comments apply to all the text filters.
|
||||
|
||||
1. `heading (includes|does not include) <search text>`
|
||||
* It matches all tasks in a section whose heading contains the string `<search text>` at least once.
|
||||
* That is, it is a sub-string search.
|
||||
* So `heading includes Day Planner` will match tasks in sections `## Monday Day Planner` and `## Day Planner for typical day`.
|
||||
* It ignores capitalization. Searches are case-insensitive.
|
||||
* So `heading includes Day Planner` will match tasks in sections `## Day Planner` and `## DAY PLANNER`.
|
||||
* Any quote characters (`'` and `"`) are included in the search text.
|
||||
* So `heading includes "Day Planner"` will match a section`## "Day Planner"`.
|
||||
* But will not match tasks with headings like `## Day Planner`.
|
||||
2. `heading (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Regular expression (or ‘regex’) searching is a powerful but advanced feature.
|
||||
* It requires thorough knowledge in order to use successfully, and not miss intended search results.
|
||||
* It is easy to write a regular expression that looks correct, but which has a special character with a non-obvious meaning.
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
## Matching multiple filters
|
||||
|
||||
Boolean combinations were introduced in Tasks 1.9.0
|
||||
|
||||
Each line of a query has to match in order for a task to be listed. In other words, lines are considered to have an 'AND' operator between them. Within each line, you can use the boolean operators `NOT`, `AND`, `OR`, `AND NOT`, `OR NOT` and `XOR`, as long as individual filters are wrapped in parentheses:
|
||||
|
||||
```autohotkey
|
||||
```tasks
|
||||
(no due date) OR (due after 2021-04-04)
|
||||
path includes GitHub
|
||||
```
|
||||
|
||||
```tasks
|
||||
due after 2021-04-04
|
||||
(path includes GitHub) AND NOT (tags include #todo)
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
For full details of combining filters with boolean operators, see [Combining Filters](https://publish.obsidian.md/tasks/Queries/Combining+Filters).
|
||||
|
||||
## Filters for Task Statuses
|
||||
|
||||
### Status
|
||||
|
||||
* `done` \- matches tasks status types `DONE`, `CANCELLED` and `NON_TASK`
|
||||
* `not done` \- matches status types with type `TODO` and `IN_PROGRESS`
|
||||
|
||||
Prior to Tasks 1.23.0, there was no concept of task status type, and so only the status symbol was used:
|
||||
|
||||
* a task with `[ ]` used to count as `not done`
|
||||
* any other character than space used to count as `done`
|
||||
|
||||
The new behaviour is more flexible and was required to introduce support for in-progress and cancelled tasks. If the original behaviour is preferred, you can change the status types of every symbol except `space` to `DONE`. See [How to set up your custom statuses](https://publish.obsidian.md/tasks/How+To/Set+up+custom+statuses).
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by status** is now possible, using `task.isDone`.
|
||||
|
||||
* `filter by function task.isDone`
|
||||
* Same as the `done` filter, but might be useful in conjunction with other expressions on the same line.
|
||||
* `filter by function ! task.isDone`
|
||||
* Same as the `not done` filter, but might be useful in conjunction with other expressions on the same line.
|
||||
|
||||
`task.status.type` (see [Status Type](https://publish.obsidian.md/tasks/Queries/Filters#Status%20Type)) gives more precision in custom filters than `task.isDone`.
|
||||
|
||||
### Status Name
|
||||
|
||||
* This searches the names given to your custom statuses.
|
||||
* For example, perhaps you might have named `[!]` as `Important`, and so this field would search the text `Important` for all tasks with that status symbol.
|
||||
* `status.name (includes|does not include) <string>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* `status.name (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
`status.name` text searching was introduced in Tasks 1.23.0.
|
||||
|
||||
For more information, including adding your own customised statuses, see [Statuses](https://publish.obsidian.md/tasks/Getting+Started/Statuses).
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by status names** is now possible, using `task.status.name`.
|
||||
|
||||
* `filter by function task.status.name === 'Unknown'`
|
||||
* Find all tasks with custom statuses not yet added to the Tasks settings.
|
||||
|
||||
### Status Type
|
||||
|
||||
* `status.type (is|is not) (TODO|DONE|IN_PROGRESS|CANCELLED|NON_TASK)`
|
||||
* The values `TODO` etc are case-insensitive: you can use `in_progress`, for example
|
||||
* This searches the types you have given to your custom statuses.
|
||||
* This search is efficient if you wish to find all tasks that are `IN_PROGRESS`, and you have set up your statuses to have `[/]`, `[d]` and perhaps several others all treated as `IN_PROGRESS`.
|
||||
* To search for multiple possible status types:
|
||||
* To exclude multiple values, you can use multiple `status.type is not` lines.
|
||||
* To allow multiple values, use a boolean combination, for example: `( status.type is TODO ) OR ( status.type is IN_PROGRESS )`.
|
||||
* Or see the 'custom filtering' examples below.
|
||||
|
||||
`status.type` text searching was introduced in Tasks 1.23.0.
|
||||
|
||||
For more information, including adding your own customised statuses, see [Statuses](https://publish.obsidian.md/tasks/Getting+Started/Statuses).
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by status type** is now possible, using `task.status.type`.
|
||||
|
||||
* `filter by function task.status.type === 'NON_TASK'`
|
||||
* Find tasks of type `NON_TASK`.
|
||||
* `filter by function 'TODO,IN_PROGRESS'.includes(task.status.type)`
|
||||
* Find tasks that are either type `TODO` or type `IN_PROGRESS`.
|
||||
* This can be more convenient than doing Boolean `OR` searches.
|
||||
* `filter by function ! 'NON_TASK,CANCELLED'.includes(task.status.type)`
|
||||
* Find tasks that are not type `NON_TASK` and not type `CANCELLED`.
|
||||
|
||||
### Status Symbol
|
||||
|
||||
There is no built-in instruction to filter by status symbols.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by status symbol** is now possible, using `task.status.symbol`.
|
||||
|
||||
* `filter by function task.status.symbol === '-'`
|
||||
* Find tasks with a checkbox `[-]`, which is conventionally used to mean "cancelled".
|
||||
* `filter by function task.status.symbol !== ' '`
|
||||
* Find tasks with anything but the space character as their status symbol, that is, without the checkbox `[ ]`.
|
||||
* `filter by function task.status.symbol === 'P' || task.status.symbol === 'C' || task.status.symbol === 'Q' || task.status.symbol === 'A'`
|
||||
* Find tasks with status symbol `P`, `C`, `Q` or `A`.
|
||||
* This can get quite verbose, the more symbols you want to search for.
|
||||
* `filter by function 'PCQA'.includes(task.status.symbol)`
|
||||
* Find tasks with status symbol `P`, `C`, `Q` or `A`.
|
||||
* This is a convenient shortcut over a longer statement testing each allowed value independently.
|
||||
* `filter by function !' -x/'.includes(task.status.symbol)`
|
||||
* Find tasks with any status symbol not supported by Tasks in the default settings.
|
||||
|
||||
### Next Status Symbol
|
||||
|
||||
There is no built-in instruction to filter by next status symbols.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by next status symbol** is now possible, using `task.status.nextSymbol`.
|
||||
|
||||
* `filter by function task.status.symbol === task.status.nextSymbol`
|
||||
* Find tasks that toggle to themselves, because the next symbol is the same as the current symbol.
|
||||
|
||||
### Status Examples
|
||||
|
||||
Find any tasks that have status symbols you have not yet added to your Tasks settings:
|
||||
|
||||
```routeros
|
||||
```tasks
|
||||
status.name includes unknown
|
||||
group by path
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Filters for Dates in Tasks
|
||||
|
||||
### Due Date
|
||||
|
||||
* `no due date`
|
||||
* `has due date`
|
||||
* `due (before|after|on) <date>`
|
||||
* `due (before|after|in) <date range>`
|
||||
* `YYYY-MM-DD YYYY-MM-DD`
|
||||
* `(last|this|next) (week|month|quarter|year)`
|
||||
* `(YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)`
|
||||
* `due date is invalid`
|
||||
|
||||
For more information, see [Due date](https://publish.obsidian.md/tasks/Getting+Started/Dates#Due%20date).
|
||||
|
||||
* `has due date` was introduced in Tasks 1.6.0.
|
||||
* `due date is invalid` was introduced in Tasks 1.16.0.
|
||||
* `due (before|after|in) <date range>` searches were introduced in Tasks 2.0.0.
|
||||
* `due (before|after|in) (YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)` searches were introduced in Tasks 3.1.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by due date** is now possible, using `task.due`.
|
||||
|
||||
These examples all use `task.due` property, which is a `TasksDate` object. You can see the current [TasksDate source code](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/src/Scripting/TasksDate.ts), to explore its capabilities.
|
||||
|
||||
* `filter by function task.due.format('dddd') === 'Tuesday'`
|
||||
* Find tasks due on Tuesdays, that is, any Tuesday.
|
||||
* On non-English systems, you may need to supply the day of the week in the local language.
|
||||
|
||||
For users who are comfortable with JavaScript, these more complicated examples may also be of interest:
|
||||
|
||||
* `filter by function task.due.moment?.isSameOrBefore(moment(), 'day') || false`
|
||||
* Find all tasks due today or earlier.
|
||||
* `moment()` returns the current date and time, which we need to convert to the start of the day.
|
||||
* As the second parameter determines the precision, and not just a single value to check, using 'day' will check for year, month and day.
|
||||
* See the documentation of [isSameOrBefore](https://momentjscom.readthedocs.io/en/latest/moment/05-query/04-is-same-or-before/).
|
||||
* `filter by function task.due.moment?.isSameOrAfter(moment(), 'day') || false`
|
||||
* Due today or later.
|
||||
* `filter by function task.due.moment?.isSame(moment('2023-05-31'), 'day') || false`
|
||||
* Find all tasks due on 31 May 2023.
|
||||
* `filter by function task.due.moment?.isSame(moment('2023-05-31'), 'week') || false`
|
||||
* Find all tasks due in the week of 31 May 2023.
|
||||
|
||||
### Done Date
|
||||
|
||||
* `no done date`
|
||||
* `has done date`
|
||||
* `done (before|after|on) <date>`
|
||||
* `done (before|after|in) <date range>`
|
||||
* `YYYY-MM-DD YYYY-MM-DD`
|
||||
* `(last|this|next) (week|month|quarter|year)`
|
||||
* `(YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)`
|
||||
* `done date is invalid`
|
||||
|
||||
* `no done date` and `has done date` were introduced in Tasks 1.7.0.
|
||||
* `done date is invalid` was introduced in Tasks 1.16.0.
|
||||
* `done (before|after|in) <date range>` searches were introduced in Tasks 2.0.0.
|
||||
* `done (before|after|in) (YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)` searches were introduced in Tasks 3.1.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by done date** is now possible, using `task.done`.
|
||||
|
||||
* `filter by function task.done.format('dddd') === 'Thursday'`
|
||||
* Find tasks done on Thursdays, that is, any Thursday.
|
||||
* On non-English systems, you may need to supply the day of the week in the local language.
|
||||
|
||||
### Scheduled Date
|
||||
|
||||
* `no scheduled date`
|
||||
* `has scheduled date`
|
||||
* `scheduled (before|after|on) <date>`
|
||||
* `scheduled (before|after|in) <date range>`
|
||||
* `YYYY-MM-DD YYYY-MM-DD`
|
||||
* `(last|this|next) (week|month|quarter|year)`
|
||||
* `(YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)`
|
||||
* `scheduled date is invalid`
|
||||
|
||||
* `has scheduled date` was introduced in Tasks 1.6.0.
|
||||
* `scheduled date is invalid` was introduced in Tasks 1.16.0.
|
||||
* `scheduled (before|after|in) <date range>` searches were introduced in Tasks 2.0.0.
|
||||
* `scheduled (before|after|in) (YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)` searches were introduced in Tasks 3.1.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by scheduled date** is now possible, using `task.scheduled`.
|
||||
|
||||
* `filter by function task.scheduled.format('dddd') === 'Wednesday'`
|
||||
* Find tasks scheduled on Wednesdays, that is, any Wednesday.
|
||||
* On non-English systems, you may need to supply the day of the week in the local language.
|
||||
|
||||
### Start Date
|
||||
|
||||
* `no start date`
|
||||
* `has start date`
|
||||
* `starts (before|after|on) <date>`
|
||||
* `starts (before|after|in) <date range>`
|
||||
* `YYYY-MM-DD YYYY-MM-DD`
|
||||
* `(last|this|next) (week|month|quarter|year)`
|
||||
* `(YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)`
|
||||
* `start date is invalid`
|
||||
|
||||
* `has start date` was Introduced in Tasks 1.6.0.
|
||||
* `start date is invalid` was introduced in Tasks 1.16.0.
|
||||
* `starts (before|after|in) <date range>` searches were introduced in Tasks 2.0.0.
|
||||
* `starts (before|after|in) (YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)` searches were introduced in Tasks 3.1.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by start date** is now possible, using `task.start`.
|
||||
|
||||
* `filter by function task.start.format('dddd') === 'Sunday'`
|
||||
* Find tasks starting on Sundays, that is, any Sunday.
|
||||
* On non-English systems, you may need to supply the day of the week in the local language.
|
||||
|
||||
#### Making Start Date only find tasks with Start
|
||||
|
||||
When filtering queries by [start date](https://publish.obsidian.md/tasks/Getting+Started/Dates#Start%20date), the result will include tasks without a start date. This way, you can use the start date as a filter to filter out any tasks that you cannot yet work on.
|
||||
|
||||
Such filter could be:
|
||||
|
||||
```vala
|
||||
```tasks
|
||||
# Find tasks which:
|
||||
# EITHER start before today or earlier
|
||||
# OR have no start date:
|
||||
starts before tomorrow
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
To find tasks which really do start before tomorrow:
|
||||
|
||||
```autohotkey
|
||||
```tasks
|
||||
# Find tasks which start today or earlier:
|
||||
( (starts before tomorrow) AND (has start date) )
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
See [created date](https://publish.obsidian.md/tasks/Getting+Started/Dates#Created%20date) for how to make Tasks record the created date on any task lines that it creates.
|
||||
|
||||
* `no created date`
|
||||
* `has created date`
|
||||
* `created (before|after|on) <date>`
|
||||
* `created (before|after|in) <date range>`
|
||||
* `YYYY-MM-DD YYYY-MM-DD`
|
||||
* `(last|this|next) (week|month|quarter|year)`
|
||||
* `(YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)`
|
||||
* `created date is invalid`
|
||||
|
||||
Such a filter could be:
|
||||
|
||||
```autohotkey
|
||||
```tasks
|
||||
created before tomorrow
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
* Created date was introduced in Tasks 2.0.0.
|
||||
* `created (before|after|in) (YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)` searches were introduced in Tasks 3.1.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by created date** is now possible, using `task.created`.
|
||||
|
||||
* `filter by function task.created.format('dddd') === 'Monday'`
|
||||
* Find tasks created on Mondays, that is, any Monday.
|
||||
* On non-English systems, you may need to supply the day of the week in the local language.
|
||||
|
||||
### Happens
|
||||
|
||||
* `happens (before|after|on) <date>`
|
||||
* `happens (before|after|in) <date range>`
|
||||
* `YYYY-MM-DD YYYY-MM-DD`
|
||||
* `(last|this|next) (week|month|quarter|year)`
|
||||
* `(YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)`
|
||||
|
||||
`happens` returns any task for a matching start date, scheduled date, _or_ due date. For example, `happens before tomorrow` will return all tasks that are starting, scheduled, or due earlier than tomorrow. If a task starts today and is due in a week from today, `happens before tomorrow` will match, because the tasks starts before tomorrow. Only one of the dates needs to match.
|
||||
|
||||
* `no happens date`
|
||||
* Return tasks where _none_ of start date, scheduled date, and due date are set.
|
||||
* `has happens date`
|
||||
* Return tasks where _any_ of start date, scheduled date, _or_ due date are set.
|
||||
|
||||
* `no happens date` and `has happens date` were introduced in Tasks 1.7.0.
|
||||
* `happens (before|after|in) <date range>` searches were introduced in Tasks 2.0.0.
|
||||
* `happens (before|after|in) (YYYY-Www|YYYY-mm|YYYY-Qq|YYYY)` searches were introduced in Tasks 3.1.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by happens date** is now possible, using `task.happens`.
|
||||
|
||||
* `filter by function task.happens.format('dddd') === 'Friday'`
|
||||
* Find tasks happens on Fridays, that is, any Friday.
|
||||
* On non-English systems, you may need to supply the day of the week in the local language.
|
||||
|
||||
### Troubleshooting date searches
|
||||
|
||||
If your date searches are giving unexpected results, add an [explain](https://publish.obsidian.md/tasks/Queries/Explaining+Queries) line to your query.
|
||||
|
||||
This will help you identify common mistakes such as:
|
||||
|
||||
* Accidentally using an invalid absolute date in a filter.
|
||||
* Using unsupported keywords in relative date ranges.
|
||||
|
||||
If relative dates in queries do not update from the previous day, and your computer was sleeping at midnight, this is likely caused by a known Chrome bug and you will need to re-open the note. See [#1289](https://github.com/obsidian-tasks-group/obsidian-tasks/issues/1289).
|
||||
|
||||
### Finding Tasks with Invalid Dates
|
||||
|
||||
* Validation of dates was introduced in Tasks 1.16.0.
|
||||
* `created date is invalid` was introduced in Tasks 2.0.0.
|
||||
|
||||
It is possible to accidentally use a non-existent date on a task signifier, such as `📅 2022-02-30`. February has at most 29 days.
|
||||
|
||||
Such tasks look like they have a date, but that date will never be found. When viewed in Reading mode, the date will be shown as `Invalid date`.
|
||||
|
||||
Any such mistakes can be found systematically with this search:
|
||||
|
||||
```pgsql
|
||||
```tasks
|
||||
(created date is invalid) OR (done date is invalid) OR (due date is invalid) OR (scheduled date is invalid) OR (start date is invalid)
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
If the above search finds any tasks with invalid dates, they are best fixed by clicking on the [backlink](https://publish.obsidian.md/tasks/Queries/Backlinks) to navigate to the incorrect line, and fixing it by directly typing in the new date.
|
||||
|
||||
If you use the 'Create or edit Task' Modal, it will discard the broken date, and there will be no information about the original, incorrect value.
|
||||
|
||||
## Filters for Other Task Properties
|
||||
|
||||
As well as the date-related searches above, these filters search other properties in individual tasks.
|
||||
|
||||
### Description
|
||||
|
||||
* `description (includes|does not include) <string>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* Disregards the global filter when matching.
|
||||
* `description (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
`regex matches` and `regex does not match` were introduced in Tasks 1.12.0.
|
||||
|
||||
For precise searches, it may help to know that `description`:
|
||||
|
||||
* first removes all each task's signifier emojis and their values,
|
||||
* then removes any global filter,
|
||||
* then removes an trailing spaces
|
||||
* and then searches the remaining text
|
||||
|
||||
For example:
|
||||
|
||||
| Global Filter | Task line | Text searched by description |
|
||||
| ---------------- | ------------------------------------------------------------------------ | ------------------------------ |
|
||||
| No global filter | '- \[ \] Do stuff ⏫ #tag1 ✅ 2022\-08\-12 #tag2/sub-tag ' | 'Do stuff #tag1 #tag2/sub-tag' |
|
||||
| #task | '- \[ \] #task Do stuff ⏫ #tag1 ✅ 2022\-08\-12 #tag2/sub-tag ' | 'Do stuff #tag1 #tag2/sub-tag' |
|
||||
| global\-filter | '- \[ \] global\-filter Do stuff ⏫ #tag1 ✅ 2022\-08\-12 #tag2/sub\-tag ' | 'Do stuff #tag1 #tag2/sub-tag' |
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by description** is now possible, using `task.description`.
|
||||
|
||||
* `filter by function task.description.length > 100`
|
||||
* Find tasks with long descriptions.
|
||||
|
||||
### Description without tags
|
||||
|
||||
Since Tasks 4.2.0, it is possible to remove tags from the descriptions in custom filters, for use in **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters)**, using `task.descriptionWithoutTags`.
|
||||
|
||||
### Priority
|
||||
|
||||
* `priority is (above|below|not)? (lowest|low|none|medium|high|highest)`
|
||||
|
||||
The available priorities are (from high to low):
|
||||
|
||||
1. 🔺 for highest priority
|
||||
2. ⏫ for high priority
|
||||
3. 🔼 for medium priority
|
||||
4. use no signifier to indicate no priority (searched for with 'none')
|
||||
5. 🔽 for low priority
|
||||
6. ⏬️ for lowest priority
|
||||
|
||||
Priorities 'lowest' and 'highest' were introduced in Tasks 3.9.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by priority name and number** is now possible, using `task.priorityName` and `task.priorityNumber`.
|
||||
|
||||
Using the priority name:
|
||||
|
||||
* `filter by function task.priorityName !== 'Normal'`
|
||||
* The same as `priority is not none`.
|
||||
|
||||
Using the priority number:
|
||||
|
||||
* `filter by function task.priorityNumber % 2 === 0`
|
||||
* Filter using the task's priority number, where Highest is 0 and Lowest is 5.
|
||||
* This artificial example finds all the tasks with even priority numbers, so Highest, Medium and Low priorities.
|
||||
|
||||
#### Examples
|
||||
|
||||
```autohotkey
|
||||
```tasks
|
||||
not done
|
||||
priority is above none
|
||||
```
|
||||
|
||||
```tasks
|
||||
priority is high
|
||||
```
|
||||
|
||||
```tasks
|
||||
not done
|
||||
priority is not none
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
### Urgency
|
||||
|
||||
There is no built-in instruction to filter by urgency.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by urgency** is now possible, using `task.urgency`.
|
||||
|
||||
Please read the following examples carefully. To use `task.urgency` with `filter by function` successfully, it is important to understand how to handle searches for non-integer numbers.
|
||||
|
||||
* `filter by function task.urgency > 8.9999`
|
||||
* Find tasks with an urgency score above `9.0`.
|
||||
* Note that limiting value used is `8.9999`.
|
||||
* Searches that compare two urgency values for 'less than' or 'more than' (using one of `>`, `>=`, `<` or `<=`) **must adjust their values slightly to allow for rounding**.
|
||||
* `filter by function task.urgency > 7.9999 && task.urgency < 11.0001`
|
||||
* Find tasks with an urgency score between `8.0` and `11.0`, inclusive.
|
||||
* `filter by function task.urgency.toFixed(2) === 1.95.toFixed(2)`
|
||||
* Find tasks with the [default urgency](https://publish.obsidian.md/tasks/Advanced/Urgency#Why%20do%20all%20my%20tasks%20have%20urgency%20score%201.95?) of `1.95`.
|
||||
* This is the correct way to do an equality or inequality search for any numeric values.
|
||||
* The `.toFixed(2)` on both sides of the `===` ensures that two numbers being compared are both rounded to the same number of decimal places (2).
|
||||
* This is important, to prevent being tripped up `10.29` being not exactly the same when comparing non-integer numbers.
|
||||
* `filter by function task.urgency.toFixed(2) !== 1.95.toFixed(2)`
|
||||
* Find tasks with any urgency other than the default score of `1.95`.
|
||||
* `filter by function task.urgency === 10.29`
|
||||
* **This will not find any tasks**.
|
||||
* Do not use raw numbers in searches for equality or inequality of any numbers, either seemingly integer or floating point ones.
|
||||
* From using `group by urgency` and reviewing the headings, we might conclude that tasks with the following values have urgency `10.19`:
|
||||
* due tomorrow,
|
||||
* have no priority symbol.
|
||||
* From this, it might be natural to presume that we can search for `task.urgency === 10.29`.
|
||||
* However, our function is checking the following values for equality:
|
||||
* `task.urgency` is approximately:
|
||||
* `10.29` is approximately:
|
||||
* These values are **not exactly equal**, so the test fails to find any matching tasks.
|
||||
|
||||
### Recurrence
|
||||
|
||||
* `is recurring`
|
||||
* `is not recurring`
|
||||
* `recurrence (includes|does not include) <part of recurrence rule>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* Note that the text searched is generated programmatically and standardised, and so may not exactly match the text in any manually typed tasks. For example, a task with `🔁 every Sunday` will be searched as `every week on Sunday`.
|
||||
* The easiest way to see the standardised recurrence rule of your tasks is to use `group by recurrence`, and review the resulting group headings.
|
||||
* `recurrence (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
`recurrence` text searching was introduced in Tasks 1.22.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by recurrence** is now possible, using `task.isRecurring` and `task.recurrenceRule`.
|
||||
|
||||
Using `task.isRecurring`:
|
||||
|
||||
* `filter by function task.isRecurring`
|
||||
* This is identical to `is recurring`.
|
||||
* It can be used with `&&` (Boolean AND) or `||` (Boolean OR) in conjunction with other conditions.
|
||||
* `filter by function !task.isRecurring`
|
||||
* This is identical to `is not recurring`.
|
||||
* It can be used with `&&` (Boolean AND) or `||` (Boolean OR) in conjunction with other conditions.
|
||||
* `filter by function (!task.isRecurring) && task.originalMarkdown.includes('🔁')`
|
||||
* Find tasks that have a **broken/invalid recurrence rule**.
|
||||
* This assumes use of the Tasks emoji format, and should of course be updated if using another format.
|
||||
* This uses knowledge of an implementation detail of Tasks, which is that recurrence rules are read and removed from the description even if they are invalid.
|
||||
* So we have to search for the recurrence marker in `task.originalMarkdown` to see whether the original task contained the recurrence signifier when `task.isRecurring` even though false.
|
||||
|
||||
* `filter by function task.recurrenceRule.includes("every week")`
|
||||
* Similar to `recurrence includes every week`, but case-sensitive.
|
||||
* `filter by function !task.recurrenceRule.includes("every week")`
|
||||
* Similar to `recurrence does not include every week`, but case-sensitive.
|
||||
* `filter by function task.recurrenceRule.includes("every week") && task.recurrenceRule.includes("when done")`
|
||||
* Find tasks that are due every week, and **do** contain `when done` in their recurrence rule.
|
||||
* `filter by function task.recurrenceRule.includes("every week") && !task.recurrenceRule.includes("when done")`
|
||||
* Find tasks that are due every week, and do **not** contain `when done` in their recurrence rule.
|
||||
|
||||
### Sub-Items
|
||||
|
||||
* `exclude sub-items`
|
||||
* When this is set, the result list will only include tasks that are not indented in their file. It will only show tasks that are top level list items in their list.
|
||||
|
||||
### Tags
|
||||
|
||||
Introduced in Tasks 1.6.0.
|
||||
|
||||
* `no tags`
|
||||
* `has tags`
|
||||
* `tags (include|do not include) <tag>` _or_
|
||||
* `tag (includes|does not include) <tag>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* Disregards the global filter when matching.
|
||||
* The `#` is optional on the tag so `#home` and `home` will work to match `#home`.
|
||||
* If the `#` is given, it must be present, so searching for `#home` will match `#home` but not `#location/home`.
|
||||
* The match is partial so `tags include foo` will match `#foo/bar` and `#foo-bar`.
|
||||
* `tags (regex matches|regex does not match) /<JavaScript-style Regex>/` _or_
|
||||
* `tag (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
* This enables tag searches that avoid sub-tags, by putting a `$` character at the end of the regular expression. See examples below.
|
||||
* If searching for sub-tags, remember to escape the slashes in regular expressions: `\/`
|
||||
|
||||
* `regex matches` and `regex does not match` were introduced in Tasks 1.13.0.
|
||||
* `no tags` and `has tags` were introduced in Tasks 2.0.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by tags** is now possible, using `task.tags`.
|
||||
|
||||
* `filter by function task.tags.length === 1`
|
||||
* Find tasks with exactly 1 tag (other than any global filter).
|
||||
* `filter by function task.tags.length > 1`
|
||||
* Find tasks with more than one tag (other than any global filter).
|
||||
|
||||
These are more complicated examples, which you might like to copy if you use tasks with [nested tags](https://help.obsidian.md/Editing+and+formatting/Tags#Nested+tags).
|
||||
|
||||
* `filter by function task.tags.find( (tag) => tag.includes('/') ) && true || false`
|
||||
* Find all tasks that have at least one nested tag.
|
||||
* `filter by function task.tags.find( (tag) => tag.split('/').length >= 3 ) && true || false`
|
||||
* Find all tasks that have at least one doubly-nested tag, such as `#context/home/ground-floor`.
|
||||
* This splits each tag at the `/` character, and counts as a match if there are at least 3 words.
|
||||
|
||||
#### Tag Query Examples
|
||||
|
||||
* `tags include #todo`
|
||||
* `tags do not include #todo`
|
||||
* `tag regex matches /#t$/`
|
||||
* Searches for a single-character tag `#t`, with no sub-tags, because `$` matches the end of the tag text.
|
||||
* `tag regex matches /#book$/i`
|
||||
* The trailing `i` means case-insensitive.
|
||||
* Searches for tags such as `#book`, `#Book`, `#BOOK` and the `$` prevents matching of `#books`, `#book/literature`, etc.
|
||||
|
||||
### Original Markdown
|
||||
|
||||
There is no built-in instruction to filter by the original markdown line.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by original markdown line** is now possible, using `task.originalMarkdown`.
|
||||
|
||||
For example, this could be used to extract information from `task.originalMarkdown` that Tasks does not parse, to use for filtering tasks.
|
||||
|
||||
## Filters for File Properties
|
||||
|
||||
These filters allow searching for tasks in particular files and sections of files.
|
||||
|
||||
### File Path
|
||||
|
||||
Note that the path includes the `.md` extension.
|
||||
|
||||
* `path (includes|does not include) <path>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* `path (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
`regex matches` and `regex does not match` were introduced in Tasks 1.12.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by file path** is now possible, using `task.file.path`.
|
||||
|
||||
* `filter by function task.file.path.includes('tasks releases/4.1.0 Release.md')`
|
||||
* Like 'path includes', except that it is **case-sensitive**: capitalisation matters.
|
||||
* `filter by function task.file.path === 'tasks releases/4.1.0 Release.md'`
|
||||
* An exact, **case-sensitive**, equality search.
|
||||
* Note that the file extension needs to be included too.
|
||||
* With built-in searches, this could only be done using a regular expression, with special characters `^` and `$`, and escaping any characters with special meaning such as `/`.
|
||||
* `filter by function task.file.path.toLocaleLowerCase() === 'TASKS RELEASES/4.1.0 RELEASE.MD'.toLocaleLowerCase()`
|
||||
* An exact, **non**\-case-sensitive, equality search.
|
||||
* By lower-casing both values, we do not have to worry about manually lower-casing them in our query.
|
||||
|
||||
### Root
|
||||
|
||||
Introduced in Tasks 3.4.0.
|
||||
|
||||
The `root` is the top-level folder of the file that contains the task, that is, the first directory in the path, which will be `/` for files in the root of the vault.
|
||||
|
||||
* `root (includes|does not include) <root>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* `root (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by root folder** is now possible, using `task.file.root`.
|
||||
|
||||
* `filter by function task.file.root === '/'`
|
||||
* Find tasks in files in the root of the vault.
|
||||
* Note that this is **case-sensitive**: capitalisation matters.
|
||||
* `filter by function task.file.root === 'Work/'`
|
||||
* Find tasks in files inside the folder `Work` which is in the root of the vault.
|
||||
* Note that this is **case-sensitive**: capitalisation matters.
|
||||
|
||||
### Folder
|
||||
|
||||
Introduced in Tasks 3.4.0.
|
||||
|
||||
This is the `folder` to the file that contains the task, which will be `/` for files in root of the vault.
|
||||
|
||||
* `folder (includes|does not include) <folder>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* `folder (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by folder** is now possible, using `task.file.folder`.
|
||||
|
||||
* `filter by function task.file.folder === "Work/Projects/"`
|
||||
* Find tasks in files in any file in the given folder **only**, and not any sub-folders.
|
||||
* The equality test, `===`, requires that the trailing slash (`/`) be included.
|
||||
* `filter by function task.file.folder.includes("Work/Projects/")`
|
||||
* Find tasks in files in any folder **and any sub-folders**.
|
||||
* `filter by function task.file.folder.includes("Work/Projects")`
|
||||
* By leaving off the trailing slash (`/`) this would also find tasks in any file inside folders such as:
|
||||
* `Work/Projects 2023/`
|
||||
* `Work/Projects Top Secret/`
|
||||
|
||||
### File Name
|
||||
|
||||
Introduced in Tasks 1.13.0.
|
||||
|
||||
Note that the file name includes the `.md` extension.
|
||||
|
||||
* `filename (includes|does not include) <filename>`
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* `filename (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Does regular expression match (case-sensitive by default).
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by file name** is now possible, using `task.file.filename`.
|
||||
|
||||
* `filter by function task.file.filename === "4.1.0 Release.md"`
|
||||
* Find tasks in files with the exact file name, but in any folder.
|
||||
* The equality test, `===`, requires that the file extension `.md` be included.
|
||||
* `filter by function task.file.filename.includes("4.1.0 Release")`
|
||||
* Find tasks in files whose name contains the given text.
|
||||
* By using `.includes()` and leaving out the file extension, this will also find files such as `14.1.0 Release.md` and `4.1.0 Release Notes.md`.
|
||||
|
||||
### Heading
|
||||
|
||||
* `heading (includes|does not include) <string>`
|
||||
* Whether or not the heading preceding the task includes the given string.
|
||||
* Always tries to match the closest heading above the task, regardless of heading level.
|
||||
* `does not include` will match a task that does not have a preceding heading in its file.
|
||||
* Matches case-insensitive (disregards capitalization).
|
||||
* `heading (regex matches|regex does not match) /<JavaScript-style Regex>/`
|
||||
* Whether or not the heading preceding the task includes the given regular expression (case-sensitive by default).
|
||||
* Always tries to match the closest heading above the task, regardless of heading level.
|
||||
* `regex does not match` will match a task that does not have a preceding heading in its file.
|
||||
* Essential reading: [Regular Expression Searches](https://publish.obsidian.md/tasks/Queries/Regular+Expressions).
|
||||
|
||||
`regex matches` and `regex does not match` were introduced in Tasks 1.12.0.
|
||||
|
||||
Since Tasks 4.2.0, **[custom filtering](https://publish.obsidian.md/tasks/Scripting/Custom+Filters) by heading** is now possible, using `task.heading`.
|
||||
|
||||
Heading searches can be very powerful: you can put information in headings and then write your searches to look for the information:
|
||||
|
||||
* either on the task,
|
||||
* or if it's missing from the task, then look for it in the preceding heading.
|
||||
|
||||
It is like a more generalisable version of the built-in mechanism to infer [a scheduled date from a filename](https://publish.obsidian.md/tasks/Getting+Started/Use+Filename+as+Default+Date), under your own control.
|
||||
|
||||
* `filter by function task.due.moment?.isSame('2023-06-11', 'day') || ( !task.due.moment && task.heading?.includes('2023-06-11')) || false`
|
||||
* Find takes that:
|
||||
* **or** do not have a due date, and their preceding heading contains the same date as a string: .
|
||||
* `filter by function task.due.moment?.isSame(moment(), 'day') || ( !task.due.moment && task.heading?.includes(moment().format('YYYY-MM-DD')) ) || false`
|
||||
* Find takes that:
|
||||
* **either** due on today's date,
|
||||
* **or** do not have a due date, and their preceding heading contains today's date as a string, formatted as `YYYY-MM-DD`.
|
||||
* `filter by function task.heading?.includes('#context/home') || task.tags.find( (tag) => tag === '#context/home' ) && true || false`
|
||||
* Find takes that:
|
||||
* **either** have a tag exactly matching `#context/home` on the task line,
|
||||
* **or** their preceding heading contains the text `#context/home` anywhere.
|
||||
* For demonstration purposes, this is slightly imprecise, in that it would also match nested tasks, such as `#context/home/ground-floor`.
|
||||
|
||||

|
||||
|
||||
Custom filters can extract dates and tags from headings.
|
||||
|
||||
## Appendix: Tasks 2.0.0 improvements to date filters
|
||||
|
||||
Tasks 2.0.0 introduced the concept of filtering for date ranges.
|
||||
|
||||
In all cases, this new feature improves the results of Tasks date filters.
|
||||
|
||||
This Appendix shows how the results of various searches have changes, to enable you to decide whether any existing searches need to be updated.
|
||||
|
||||
### due (before|on|in||after) absolute date: results unchanged
|
||||
|
||||
| keyword | Tasks 1.25.0 and earlier | Tasks 2.0.0 onwards |
|
||||
| --------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------- |
|
||||
| **Summary** | All searches behave logically, using the correct date. | Identical behaviour to previous releases. |
|
||||
| before | \=> due date is before2023-02-09 (Thursday 9th February 2023) | \=> due date is before2023-02-09 (Thursday 9th February 2023) |
|
||||
| on | \=> due date is on2023-02-09 (Thursday 9th February 2023) | \=> due date is on2023-02-09 (Thursday 9th February 2023) |
|
||||
| in | \=> due date is on2023-02-09 (Thursday 9th February 2023) | \=> due date is on2023-02-09 (Thursday 9th February 2023) |
|
||||
| \=> due date is on2023-02-09 (Thursday 9th February 2023) | \=> due date is on2023-02-09 (Thursday 9th February 2023) | |
|
||||
| after | \=> due date is after2023-02-09 (Thursday 9th February 2023) | \=> due date is after2023-02-09 (Thursday 9th February 2023) |
|
||||
|
||||
### due (before|on|in||after) absolute date range: results improved
|
||||
|
||||
| keyword | Tasks 1.25.0 and earlier | Tasks 2.0.0 onwards |
|
||||
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Summary** | The second date is ignored: only the first date is used. | The values are interpreted as a date range.after takes the end date in to account. |
|
||||
| before | \=> due date is before2023-02-07 (Tuesday 7th February 2023) | \=> due date is before2023-02-07 (Tuesday 7th February 2023) |
|
||||
| on | \=> due date is on2023-02-07 (Tuesday 7th February 2023) | \=> due date is between2023-02-07 (Tuesday 7th February 2023) and2023-02-11 (Saturday 11th February 2023) inclusive |
|
||||
| in | \=> due date is on2023-02-07 (Tuesday 7th February 2023) | \=> due date is between2023-02-07 (Tuesday 7th February 2023) and2023-02-11 (Saturday 11th February 2023) inclusive |
|
||||
| \=> due date is on2023-02-07 (Tuesday 7th February 2023) | \=> due date is between2023-02-07 (Tuesday 7th February 2023) and2023-02-11 (Saturday 11th February 2023) inclusive | |
|
||||
| after | \=> due date is after2023-02-07 (Tuesday 7th February 2023) | \=> due date is after2023-02-11 (Saturday 11th February 2023) |
|
||||
|
||||
### due (before|on|in||after) last week: results improved
|
||||
|
||||
Differences in interpretation of various **[relative due date range](https://publish.obsidian.md/tasks/Queries/Filters#Relative%20date%20ranges)** filters, when run on (Friday 10th February 2023):
|
||||
|
||||
| keyword | Tasks 1.25.0 and earlier | Tasks 2.0.0 onwards |
|
||||
| --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Summary** | last week is interpreted as a single date: 7 days before the current date. | last week is interpreted as a date range:the previous Monday to Sunday.after takes the end date in to account. |
|
||||
| before | due before last week \=> due date is before2023-02-03 (Friday 3rd February 2023) | due before last week \=> due date is before2023-01-30 (Monday 30th January 2023) |
|
||||
| on | due on last week \=> due date is on2023-02-03 (Friday 3rd February 2023) | due on last week \=> due date is between2023-01-30 (Monday 30th January 2023) and2023-02-05 (Sunday 5th February 2023) inclusive |
|
||||
| in | due in last week \=> due date is on2023-02-03 (Friday 3rd February 2023) | due in last week \=> due date is between2023-01-30 (Monday 30th January 2023) and2023-02-05 (Sunday 5th February 2023) inclusive |
|
||||
| due last week \=> due date is on2023-02-03 (Friday 3rd February 2023) | due last week \=> due date is between2023-01-30 (Monday 30th January 2023) and2023-02-05 (Sunday 5th February 2023) inclusive | |
|
||||
| after | due after last week \=> due date is after2023-02-03 (Friday 3rd February 2023) | due after last week \=> due date is after2023-02-05 (Sunday 5th February 2023) |
|
||||
|
||||
### due (before|on|in||after) this week: results improved
|
||||
|
||||
Differences in interpretation of various **[relative due date range](https://publish.obsidian.md/tasks/Queries/Filters#Relative%20date%20ranges)** filters, when run on (Friday 10th February 2023):
|
||||
|
||||
| keyword | Tasks 1.25.0 and earlier | Tasks 2.0.0 onwards |
|
||||
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Summary** | this week is interpreted as a single date:the sunday before the current date | this week is interpreted as a date range:the Monday to Sunday containing the current day.after takes the end date in to account. |
|
||||
| before | due before this week \=> due date is before2023-02-05 (Sunday 5th February 2023) | due before this week \=> due date is before2023-02-06 (Monday 6th February 2023) |
|
||||
| on | due on this week \=> due date is on2023-02-05 (Sunday 5th February 2023) | due on this week \=> due date is between2023-02-06 (Monday 6th February 2023) and2023-02-12 (Sunday 12th February 2023) inclusive |
|
||||
| in | due in this week \=> due date is on2023-02-05 (Sunday 5th February 2023) | due in this week \=> due date is between2023-02-06 (Monday 6th February 2023) and2023-02-12 (Sunday 12th February 2023) inclusive |
|
||||
| due this week \=> due date is on2023-02-05 (Sunday 5th February 2023) | due this week \=> due date is between2023-02-06 (Monday 6th February 2023) and2023-02-12 (Sunday 12th February 2023) inclusive | |
|
||||
| after | due after this week \=> due date is after2023-02-05 (Sunday 5th February 2023) | due after this week \=> due date is after2023-02-12 (Sunday 12th February 2023) |
|
||||
|
||||
### due (before|on|in||after) next week: results improved
|
||||
|
||||
Differences in interpretation of various **[relative due date range](https://publish.obsidian.md/tasks/Queries/Filters#Relative%20date%20ranges)** filters, when run on (Friday 10th February 2023):
|
||||
|
||||
| keyword | Tasks 1.25.0 and earlier | Tasks 2.0.0 onwards |
|
||||
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Summary** | next week is interpreted as a single date: 7 days after the current date. | next week is interpreted as a date range:the next Monday to Sunday.after takes the end date in to account. |
|
||||
| before | due before next week \=> due date is before2023-02-17 (Friday 17th February 2023) | due before next week \=> due date is before2023-02-13 (Monday 13th February 2023) |
|
||||
| on | due on next week \=> due date is on2023-02-17 (Friday 17th February 2023) | due on next week \=> due date is between2023-02-13 (Monday 13th February 2023) and2023-02-19 (Sunday 19th February 2023) inclusive |
|
||||
| in | due in next week \=> due date is on2023-02-17 (Friday 17th February 2023) | due in next week \=> due date is between2023-02-13 (Monday 13th February 2023) and2023-02-19 (Sunday 19th February 2023) inclusive |
|
||||
| due next week \=> due date is on2023-02-17 (Friday 17th February 2023) | due next week \=> due date is between2023-02-13 (Monday 13th February 2023) and2023-02-19 (Sunday 19th February 2023) inclusive | |
|
||||
| after | due after next week \=> due date is after2023-02-17 (Friday 17th February 2023) | due after next week \=> due date is after2023-02-19 (Sunday 19th February 2023) |
|
||||
|
||||
Filters
|
||||
@@ -1,550 +0,0 @@
|
||||
---
|
||||
id: id-generated-by-omnivore
|
||||
title: Grouping - Tasks User Guide - Obsidian Publish
|
||||
tags:
|
||||
- obsidian-tasks
|
||||
state: ARCHIVED
|
||||
date_saved: 2023-07-16 10:23:40
|
||||
date_read: 2023-07-16 12:18:14
|
||||
date_archived: 2023-07-16T10:05:16.592Z
|
||||
---
|
||||
|
||||
# Grouping - Tasks User Guide - Obsidian Publish
|
||||
|
||||
#Omnivore
|
||||
|
||||
[Read on Omnivore](https://omnivore.app/)
|
||||
[Read Original](https://publish.obsidian.md/tasks/Queries/Grouping)
|
||||
|
||||
## Webpage
|
||||
|
||||
## Grouping
|
||||
|
||||
## Contents
|
||||
|
||||
This page is long. Here are some links to the main sections:
|
||||
|
||||
* [Basics](https://publish.obsidian.md/tasks/Queries/Grouping#Basics)
|
||||
* [Custom Groups](https://publish.obsidian.md/tasks/Queries/Grouping#Custom%20Groups)
|
||||
* [Group by Task Statuses](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20Task%20Statuses)
|
||||
* [Group by Dates in Tasks](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20Dates%20in%20Tasks)
|
||||
* [Group by Other Task Properties](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20Other%20Task%20Properties)
|
||||
* [Group by File Properties](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20File%20Properties)
|
||||
* [Multiple groups](https://publish.obsidian.md/tasks/Queries/Grouping#Multiple%20groups)
|
||||
* [Refining groups](https://publish.obsidian.md/tasks/Queries/Grouping#Refining%20groups)
|
||||
* [Notes](https://publish.obsidian.md/tasks/Queries/Grouping#Notes)
|
||||
* [Screenshots](https://publish.obsidian.md/tasks/Queries/Grouping#Screenshots)
|
||||
* [Examples](https://publish.obsidian.md/tasks/Queries/Grouping#Examples)
|
||||
|
||||
## Basics
|
||||
|
||||
Introduced in Tasks 1.6.0.
|
||||
|
||||
By default, Tasks displays tasks in a single list.
|
||||
|
||||
To divide the matching tasks up with headings, you can add `group by` lines to the query.
|
||||
|
||||
## Custom Groups
|
||||
|
||||
`group by function` was introduced in Tasks 4.0.0.
|
||||
|
||||
Tasks provides many built-in grouping options, but sometimes they don't quite do what is wanted by all users.
|
||||
|
||||
Now Tasks has a powerful mechanism for you to create your own **custom groups**, offering incredible flexibility.
|
||||
|
||||
There are many examples of the custom grouping instruction `group by function` in the documentation below, with explanations, for when the `group by` instructions built in to Tasks do not satisfy your preferences.
|
||||
|
||||
You can find out more about this very powerful facility in [Custom Grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping).
|
||||
|
||||
## Group by Task Statuses
|
||||
|
||||
For more information, including adding your own customised statuses, see [Statuses](https://publish.obsidian.md/tasks/Getting+Started/Statuses).
|
||||
|
||||
### Status
|
||||
|
||||
* `group by status` (Done or Todo, which is capitalized for visibility in the headings)
|
||||
* Note that the Done group is displayed before the Todo group, which differs from the Sorting ordering of this property.
|
||||
* `Done` is used for tasks status types `DONE`, `CANCELLED` and `NON_TASK`
|
||||
* `Todo` is used for status types with type `TODO` and `IN_PROGRESS`
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status** is now possible.
|
||||
|
||||
* `group by function task.isDone ? "Action Required" : "Nothing To Do"`
|
||||
* Use JavaScript's ternary operator to choose what to do for true (after the ?) and false (after the :) values.
|
||||
|
||||
### Status Name
|
||||
|
||||
* `group by status.name`
|
||||
* This groups by the names you give to your custom statuses, in alphabetical order.
|
||||
|
||||
`group by status.name` was introduced in Tasks 1.23.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status names** is now possible.
|
||||
|
||||
* `group by function task.status.name`
|
||||
* Identical to "group by status.name".
|
||||
* `group by function task.status.name.toUpperCase()`
|
||||
* Convert the status names to capitals.
|
||||
|
||||
### Status Type
|
||||
|
||||
* `group by status.type`
|
||||
* This groups by the types you have given to your custom statuses.
|
||||
* The groups will appear in this order, and with these group names:
|
||||
* `IN_PROGRESS`
|
||||
* `TODO`
|
||||
* `DONE`
|
||||
* `CANCELLED`
|
||||
* `NON_TASK`
|
||||
|
||||
`group by status.type` was introduced in Tasks 1.23.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status types** is now possible.
|
||||
|
||||
* `group by function task.status.type`
|
||||
* Unlike "group by status.type", this sorts the status types in alphabetical order.
|
||||
|
||||
### Status Symbol
|
||||
|
||||
There is no built-in instruction to group by status symbols.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status symbol** is now possible.
|
||||
|
||||
* `group by function "Status symbol: " + task.status.symbol.replace(" ", "space")`
|
||||
* Group by the status symbol, making space characters visible.
|
||||
|
||||
### Next Status Symbol
|
||||
|
||||
There is no built-in instruction to group by next status symbols.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by next status symbol** is now possible.
|
||||
|
||||
* `group by function "Next status symbol: " + task.status.nextSymbol.replace(" ", "space")`
|
||||
* Group by the next status symbol, making space characters visible.
|
||||
|
||||
## Group by Dates in Tasks
|
||||
|
||||
### Due Date
|
||||
|
||||
* `group by due`
|
||||
* The due date of the task, including the week-day, or `No due date`.
|
||||
|
||||
* `due` grouping option was introduced in Tasks 1.7.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by due date** is now possible.
|
||||
|
||||
These examples all use `task.due` property, which is a `TasksDate` object. You can see the current [TasksDate source code](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/src/Scripting/TasksDate.ts), to explore its capabilities.
|
||||
|
||||
* `group by function task.due.format("YYYY-MM-DD dddd")`
|
||||
* Like "group by due", except it uses no heading, instead of a heading "No due date", if there is no due date.
|
||||
* `group by function task.due.formatAsDate()`
|
||||
* Format date as YYYY-MM-DD or empty string (so no heading) if there is no due date.
|
||||
* `group by function task.due.formatAsDateAndTime()`
|
||||
* Format date as YYYY-MM-DD HH:mm or empty string if no due date.
|
||||
* Note:
|
||||
* This is shown for demonstration purposes.
|
||||
* Currently the Tasks plugin does not support storing of times.
|
||||
* Do not add times to your tasks, as it will break the reading of task data.
|
||||
* `group by function task.due.format("YYYY[%%]-MM[%%] MMM", "no due date")`
|
||||
* Group by month, for example `2023%%-05%% May` ...
|
||||
* ... which gets rendered by Obsidian as `2023 May`.
|
||||
* Or show a default heading "no due date" if no date.
|
||||
* The hidden month number is added, commented-out between two `%%` strings, to control the sort order of headings.
|
||||
* To escape characters in format strings, you can wrap the characters in square brackets (here, `[%%]`).
|
||||
* `group by function task.due.format("YYYY[%%]-MM[%%] MMM [- Week] WW")`
|
||||
* Group by month and week number, for example `2023%%-05%% May - Week 22` ...
|
||||
* ... which gets rendered by Obsidian as `2023 May - Week 22`.
|
||||
* If the month number is not embedded, in some years the first or last week of the year is displayed in a non-logical order.
|
||||
|
||||
DON'T PANIC! For users who are comfortable with JavaScript, these more complicated examples may also be of interest:
|
||||
|
||||
* `group by function task.due.moment?.fromNow() || ""`
|
||||
* Group by the time from now, for example "8 days ago".
|
||||
* Because Moment.fromNow() is not provided by TasksDate, we need special code for when there is no date value.
|
||||
* Whilst interesting, the alphabetical sort order makes the headings a little hard to read.
|
||||
* `group by function task.due.format("dddd")`
|
||||
* Group by day of the week (Monday, Tuesday, etc).
|
||||
* The day names are sorted alphabetically.
|
||||
* `group by function task.due.format("[%%]d[%%]dddd")`
|
||||
* Group by day of the week (Sunday, Monday, Tuesday, etc).
|
||||
* The day names are sorted in date order, starting with Sunday.
|
||||
* `group by function task.due.moment ? ( task.due.moment.day() === 0 ? task.due.format("[%%][8][%%]dddd") : task.due.format("[%%]d[%%]dddd") ) : "Undated"`
|
||||
* Group by day of the week (Monday, Tuesday, etc).
|
||||
* The day names are sorted in date order, starting with Monday.
|
||||
* Tasks without due dates are displayed at the end, under a heading "Undated".
|
||||
* This is best understood by pasting it in to a Tasks block in Obsidian and then deleting parts of the expression.
|
||||
* The key technique is to say that if the day is Sunday (`0`), then force it to be displayed as date number `8`, so it comes after the other days of the week.
|
||||
* `group by function (!task.due.moment) ? '%%4%% Undated' : result = task.due.moment.isBefore(moment(), 'day') ? '%%1%% Overdue' : result = task.due.moment.isSame(moment(), 'day') ? '%%2%% Today' : '%%3%% Future'`
|
||||
* Group task due dates in to 4 broad categories: `Overdue`, `Today`, `Future` and `Undated`, displayed in that order.
|
||||
* Try this on a line before `group by due` if there are a lot of due date headings, and you would like them to be broken down in to some kind of structure.
|
||||
* A limitation of Tasks expressions is that they each need to fit on a single line, so this uses nested ternary operators, making it powerful but very hard to read.
|
||||
* In fact, for ease of development and testing, it was written in a full-fledged development environment as a series of if/else blocks, and then automatically refactored in these nested ternary operators.
|
||||
* `group by function (!task.due.moment) ? '%%4%% ==Undated==' : result = task.due.moment.isBefore(moment(), 'day') ? '%%1%% ==Overdue==' : result = task.due.moment.isSame(moment(), 'day') ? '%%2%% ==Today==' : '%%3%% ==Future=='`
|
||||
* As above, but the headings `Overdue`, `Today`, `Future` and `Undated` are highlighted.
|
||||
* See the sample screenshot below.
|
||||
|
||||

|
||||
|
||||
Sample image showing tasks grouped first by highlighted words `Overdue`, `Today`, `Future` and `Undated`, and then by individual due date.
|
||||
|
||||
### Done Date
|
||||
|
||||
* `group by done`
|
||||
* The done date of the task, including the week-day, or `No done date`.
|
||||
|
||||
* `done` grouping option was introduced in Tasks 1.7.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by done date** is now possible.
|
||||
|
||||
* `group by function task.done.format("YYYY-MM-DD dddd")`
|
||||
* Like "group by done", except it uses an empty string instead of "No done date" if there is no done date.
|
||||
|
||||
### Scheduled Date
|
||||
|
||||
* `group by scheduled`
|
||||
* The scheduled date of the task, including the week-day, or `No scheduled date`.
|
||||
|
||||
* `scheduled` grouping option was introduced in Tasks 1.7.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by scheduled date** is now possible.
|
||||
|
||||
* `group by function task.scheduled.format("YYYY-MM-DD dddd")`
|
||||
* Like "group by scheduled", except it uses an empty string instead of "No scheduled date" if there is no scheduled date.
|
||||
|
||||
### Start Date
|
||||
|
||||
* `group by start`
|
||||
* The start date of the task, including the week-day, or `No start date`.
|
||||
|
||||
* `start` grouping option was introduced in Tasks 1.7.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by start date** is now possible.
|
||||
|
||||
* `group by function task.start.format("YYYY-MM-DD dddd")`
|
||||
* Like "group by start", except it uses an empty string instead of "No start date" if there is no start date.
|
||||
|
||||
* `group by created`
|
||||
* The created date of the task, including the week-day, or `No created date`.
|
||||
|
||||
`created` grouping option was introduced in Tasks 2.0.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by created date** is now possible.
|
||||
|
||||
* `group by function task.created.format("YYYY-MM-DD dddd")`
|
||||
* Like "group by created", except it uses an empty string instead of "No created date" if there is no created date.
|
||||
|
||||
### Happens
|
||||
|
||||
* `group by happens`
|
||||
* The earliest of start date, scheduled date, and due date, including the week-day, or `No happens date` if none of those are set.
|
||||
|
||||
`happens` grouping option was introduced in Tasks 1.11.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by happens date** is now possible.
|
||||
|
||||
* `group by function task.happens.format("YYYY-MM-DD dddd")`
|
||||
* Like "group by happens", except it uses an empty string instead of "No happens date" if there is no happens date.
|
||||
|
||||
## Group by Other Task Properties
|
||||
|
||||
As well as the date-related groups above, groups can be created from properties in individual tasks.
|
||||
|
||||
### Description
|
||||
|
||||
There is no built-in instruction to group by description.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by description** is now possible.
|
||||
|
||||
* `group by function task.description`
|
||||
* group by description.
|
||||
* This might be useful for finding completed recurrences of the same task.
|
||||
* `group by function task.description.toUpperCase()`
|
||||
* Convert the description to capitals.
|
||||
* `group by function task.description.slice(0, 25)`
|
||||
* Truncate descriptions to at most their first 25 characters, and group by that string.
|
||||
* `group by function task.description.replace('short', '==short==')`
|
||||
* Highlight the word "short" in any group descriptions.
|
||||
|
||||
### Description without tags
|
||||
|
||||
Since Tasks 4.2.0, it is possible to remove tags from the descriptions in custom groups, for use in **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping)**.
|
||||
|
||||
The value `task.descriptionWithoutTags` returns a copy of the description with all the tags removed, so that you can group together any tasks whose descriptions differ only by their tags.
|
||||
|
||||
* `group by function task.descriptionWithoutTags`
|
||||
* Like `group by description`, but it removes any tags from the group headings.
|
||||
* This might be useful for finding completed recurrences of the same task, even if the tags differ in some recurrences.
|
||||
|
||||
### Priority
|
||||
|
||||
* `group by priority`
|
||||
* The priority of the task, namely one of:
|
||||
* `Highest priority`
|
||||
* `High priority`
|
||||
* `Medium priority`
|
||||
* `Normal priority`
|
||||
* `Low priority`
|
||||
* `Lowest priority`
|
||||
|
||||
* `priority` grouping option was introduced in Tasks 1.11.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by priority name and number** is now possible.
|
||||
|
||||
Using the priority name:
|
||||
|
||||
* `group by function task.priorityName`
|
||||
* Group by the task's priority name.
|
||||
* The priority names are displayed in alphabetical order.
|
||||
* Note that the default priority is called 'Normal', as opposed to with `group by priority` which calls the default 'None'.
|
||||
* `group by function '%%' + task.priorityNumber.toString() + '%%' + task.priorityName +' priority'`
|
||||
* Group by the task's priority name.
|
||||
* The hidden priority number ensures that the headings are written from highest to lowest priority.
|
||||
* Note that the default priority is called 'Normal', as opposed to with `group by priority` which calls the default 'None'.
|
||||
|
||||
Using the priority number:
|
||||
|
||||
* `group by function task.priorityNumber`
|
||||
* Group by the task's priority number, where Highest is 0 and Lowest is 5.
|
||||
|
||||
### Urgency
|
||||
|
||||
* `group by urgency` ([urgency](https://publish.obsidian.md/tasks/Advanced/Urgency))
|
||||
* The groups run from the highest urgency to the lowest.
|
||||
* You can reverse this with `group by urgency reverse`.
|
||||
|
||||
* `urgency` grouping option was introduced in Tasks 3.6.0.
|
||||
* In Tasks 4.0.0 the order of `group by urgency` was reversed, to put most urgent tasks first. Add or remove the word `reverse` to get the original order.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by urgency** is now possible.
|
||||
|
||||
* `group by function task.urgency.toFixed(3)`
|
||||
* Show the urgency to 3 decimal places, unlike the built-in "group by urgency" which uses 2.
|
||||
|
||||
### Recurrence
|
||||
|
||||
* `group by recurring`
|
||||
* Whether the task is recurring: either `Recurring` or `Not Recurring`.
|
||||
* `group by recurrence`
|
||||
* The recurrence rule of the task, for example `every week on Sunday`, or `None` for non-recurring tasks.
|
||||
* Note that the text displayed is generated programmatically and standardised, and so may not exactly match the text in any manually typed tasks. For example, a task with `🔁 every Sunday` is grouped in `every week on Sunday`.
|
||||
|
||||
* `recurring` and `recurrence` grouping options were introduced in Tasks 1.11.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by recurrence** is now possible.
|
||||
|
||||
* `group by function task.isRecurring ? "Recurring" : "Non-Recurring"`
|
||||
* Use JavaScript's ternary operator to choose what to do for true (after the ?) and false (after the :) values.
|
||||
|
||||
* `group by function task.recurrenceRule.replace('when done', '==when done==')`
|
||||
* Group by recurrence rule, highlighting any occurrences of the words "when done".
|
||||
|
||||
### Tags
|
||||
|
||||
* `group by tags`
|
||||
* The tags of the tasks or `(No tags)`. If the task has multiple tags, it will show up under every tag.
|
||||
|
||||
* `tags` grouping option was introduced in Tasks 1.10.0.
|
||||
|
||||
* `group by function task.tags`
|
||||
* Like "group by tags" except that tasks with no tags have no heading instead of "(No tags)".
|
||||
* `group by function task.tags.join(", ")`
|
||||
* Tasks with multiple tags are listed once, with a heading that combines all the tags.
|
||||
* Separating with commas means the tags are clickable in the headings.
|
||||
* `group by function task.tags.sort().join(", ")`
|
||||
* As above, but sorting the tags first ensures that the final headings are independent of order of tags in the tasks.
|
||||
* `group by function task.tags.filter( (tag) => tag.includes("#context/") )`
|
||||
* Only create headings for tags that contain "#context/".
|
||||
* `group by function task.tags.filter( (tag) => ! tag.includes("#tag") )`
|
||||
* Create headings for all tags that do not contain "#tag".
|
||||
|
||||
These are more complicated examples, which you might like to copy if you use tasks with [nested tags](https://help.obsidian.md/Editing+and+formatting/Tags#Nested+tags) and wish to group them at different tag nesting levels.
|
||||
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[0].replace('#', '') )`
|
||||
* `#tag/subtag/sub-sub-tag` gives **`tag`**.
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')`
|
||||
* `#tag/subtag/sub-sub-tag` gives **`subtag`**.
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[2] ? tag.split('/').slice(2, 3) : '')`
|
||||
* `#tag/subtag/sub-sub-tag` gives **`sub-sub-tag`**.
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[3] ? tag.split('/').slice(3, 4) : '')`
|
||||
* `#tag/subtag/sub-sub-tag` gives no heading, as there is no value at the 4th level.
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[0] )`
|
||||
* `#tag/subtag/sub-sub-tag` gives **`#tag`**.
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[1] ? tag.split('/').slice(0, 2).join('/') : '')`
|
||||
* `#tag/subtag/sub-sub-tag` gives **`#tag/subtag`**.
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[2] ? tag.split('/').slice(0, 3).join('/') : '')`
|
||||
* `#tag/subtag/sub-sub-tag` gives **`#tag/subtag/sub-sub-tag`**.
|
||||
* `group by function task.tags.map( (tag) => tag.split('/')[3] ? tag.split('/').slice(0, 4).join('/') : '')`
|
||||
* `#tag/subtag/sub-sub-tag` gives no heading, as there is no value at the 4th level.
|
||||
|
||||
### Original Markdown
|
||||
|
||||
There is no built-in instruction to group by the original markdown line.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by original markdown line** is now possible.
|
||||
|
||||
For example, this could be used to extract information from `task.originalMarkdown` that Tasks does not parse, to use for grouping tasks.
|
||||
|
||||
* ``` group by function '``' + task.originalMarkdown + '``' ```
|
||||
* Group by the raw text of the task's original line in the MarkDown file as code.
|
||||
* Note the pairs of backtick characters ('\`'), to preserve even single backtick characters in the task line.
|
||||
* It's important to prevent the task checkbox (for example, '\[ \]') from being rendered in the heading, as it gets very confusing if there are checkboxes on both headings and tasks.
|
||||
* `group by function task.originalMarkdown.replace(/^[^\[\]]+\[.\] */, '')`
|
||||
* An alternative to formatting the markdown line as code is to remove everything up to the end of the checkbox.
|
||||
* Then render the rest of the task line as normal markdown.
|
||||
|
||||
## Group by File Properties
|
||||
|
||||
### File Path
|
||||
|
||||
* `group by path` (the path to the file that contains the task, that is, the folder and the filename)
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by file path** is now possible.
|
||||
|
||||
* `group by function task.file.path`
|
||||
* Like 'group by path' but includes the file extension.
|
||||
|
||||
### Root
|
||||
|
||||
* `group by root` (the top-level folder of the file that contains the task, that is, the first directory in the path, which will be `/` for files in root of the vault)
|
||||
|
||||
`root` grouping option was introduced in Tasks 1.11.0.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by root folder** is now possible.
|
||||
|
||||
* `group by function task.file.root`
|
||||
* Same as 'group by root'.
|
||||
|
||||
### Folder
|
||||
|
||||
* `group by folder` (the folder to the file that contains the task, which always ends in `/` and will be exactly `/` for files in root of the vault)
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by folder** is now possible.
|
||||
|
||||
* `group by function task.file.folder`
|
||||
* Same as 'group by folder'.
|
||||
* `group by function task.file.folder.slice(0, -1).split('/').pop() + '/'`
|
||||
* Group by the immediate parent folder of the file containing task.
|
||||
* Here's how it works:
|
||||
* '.slice(0, -1)' removes the trailing slash ('/') from the original folder.
|
||||
* '.split('/')' divides the remaining path up in to an array of folder names.
|
||||
* '.pop()' returns the last folder name, that is, the parent of the file containing the task.
|
||||
* Then the trailing slash is added back, to ensure we do not get an empty string for files in the top level of the vault.
|
||||
|
||||
### File Name
|
||||
|
||||
* `group by filename` (the link to the file that contains the task, without the `.md` extension)
|
||||
* Note that tasks from different notes with the same file name will be grouped together in the same group.
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by file name** is now possible.
|
||||
|
||||
* `group by function task.file.filename`
|
||||
* Like 'group by filename' but does not link to the file.
|
||||
* `group by function '[[' + task.file.filename.replace('.md', '') + ( task.hasHeading ? ('#' + task.heading) : '') + ']]'`
|
||||
* Like 'group by backlink' but links to the heading in the file.
|
||||
|
||||
### Backlink
|
||||
|
||||
* `group by backlink` (the text that would be shown in the task's [backlink](https://publish.obsidian.md/tasks/Queries/Backlinks), combining the task's file name and heading, but with no link added)
|
||||
|
||||
### Heading
|
||||
|
||||
* `group by heading` (the heading preceding the task, or `(No heading)` if there are no headings in the file)
|
||||
|
||||
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by heading** is now possible.
|
||||
|
||||
* `group by function (task.heading + '.md' === task.file.filename) ? '' : task.heading`
|
||||
* Group by heading, but only if the heading differs from the file name.
|
||||
* This works well immediately after a 'group by filename' line.
|
||||
* Note the three equals signs '===': these are important for safety in JavaScript.
|
||||
|
||||
## Multiple groups
|
||||
|
||||
You can add multiple `group by` query options, each on an extra line. This will create nested groups. The first group has the highest priority.
|
||||
|
||||
Each subsequent `group by` will generate a new heading-level within the existing grouping:
|
||||
|
||||
* First `group by` is displayed as `h4` headings
|
||||
* Second `group by` is displayed as `h5` headings
|
||||
* Third and subsequent `group by` are displayed as `h6` headings
|
||||
|
||||
Headings are displayed in case-sensitive alphabetical order, not the original order.
|
||||
|
||||
## Refining groups
|
||||
|
||||
### Reversing groups
|
||||
|
||||
Reversing of group headings was introduced in Tasks 3.7.0.
|
||||
|
||||
After the name of the property that you want to group by, you can add the `reverse` keyword. If given, the group headings will be reversed for that property.
|
||||
|
||||
For example:
|
||||
|
||||
* `group by due` will sort the group headings:
|
||||
* from **oldest** due date first...
|
||||
* to **newest** due date last
|
||||
* `group by due reverse` will sort the group headings:
|
||||
* from **newest** due date first...
|
||||
* to **oldest** due date last
|
||||
|
||||
The `reverse` keyword controls the order that group headings are displayed.
|
||||
|
||||
The [sort by](https://publish.obsidian.md/tasks/Queries/Sorting) facility, by contrast, controls the order in which displays are displayed _inside_ each group.
|
||||
|
||||
### Limiting group size
|
||||
|
||||
You can limit the number of tasks in each group, perhaps to work on the most important things first.
|
||||
|
||||
## Notes
|
||||
|
||||
The order of operations ensures that grouping does not modify which tasks are displayed, for example when the `limit` options are used:
|
||||
|
||||
1. all the filter instructions are run
|
||||
2. then any sorting instructions are run
|
||||
3. then any `limit` instructions are run
|
||||
4. then any grouping instructions are run
|
||||
5. then any `limit groups` instructions are run
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Before
|
||||
|
||||
Here is an example Tasks result, without any `group by` commands:
|
||||
|
||||

|
||||
|
||||
Tasks not grouped.
|
||||
|
||||
### After
|
||||
|
||||
And here is what this might look like, when grouped by folder, filename and heading:
|
||||
|
||||

|
||||
|
||||
Tasks grouped.
|
||||
|
||||
## Examples
|
||||
|
||||
Give me three levels of grouping, to indicate the locations of my tasks:
|
||||
|
||||
```routeros
|
||||
```tasks
|
||||
not done
|
||||
group by folder
|
||||
group by filename
|
||||
group by heading
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Show me tasks I need to do today - and put today's tasks first, for visibility:
|
||||
|
||||
```routeros
|
||||
```tasks
|
||||
not done
|
||||
due before tomorrow
|
||||
group by due reverse
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Grouping
|
||||
@@ -1,199 +0,0 @@
|
||||
---
|
||||
id: id-generated-by-omnivore
|
||||
title: Sorting - Tasks User Guide - Obsidian Publish
|
||||
tags:
|
||||
- obsidian-tasks
|
||||
state: ARCHIVED
|
||||
date_saved: 2023-07-16 10:23:47
|
||||
date_archived: 2023-07-16T10:05:13.986Z
|
||||
---
|
||||
|
||||
# Sorting - Tasks User Guide - Obsidian Publish
|
||||
|
||||
#Omnivore
|
||||
|
||||
[Read on Omnivore](https://omnivore.app/)
|
||||
[Read Original](https://publish.obsidian.md/tasks/Queries/Sorting)
|
||||
|
||||
## Webpage
|
||||
|
||||
## Sorting
|
||||
|
||||
## Contents
|
||||
|
||||
This page is long. Here are some links to the main sections:
|
||||
|
||||
* [Basics](https://publish.obsidian.md/tasks/Queries/Sorting#Basics)
|
||||
* [Sort by Task Statuses](https://publish.obsidian.md/tasks/Queries/Sorting#Sort%20by%20Task%20Statuses)
|
||||
* [Sort by Dates in Tasks](https://publish.obsidian.md/tasks/Queries/Sorting#Sort%20by%20Dates%20in%20Tasks)
|
||||
* [Sort by Other Task Properties](https://publish.obsidian.md/tasks/Queries/Sorting#Sort%20by%20Other%20Task%20Properties)
|
||||
* [Sort by File Properties](https://publish.obsidian.md/tasks/Queries/Sorting#Sort%20by%20File%20Properties)
|
||||
* [Multiple sort criteria](https://publish.obsidian.md/tasks/Queries/Sorting#Multiple%20sort%20criteria)
|
||||
* [Notes](https://publish.obsidian.md/tasks/Queries/Sorting#Notes)
|
||||
* [Reverse sorting](https://publish.obsidian.md/tasks/Queries/Sorting#Reverse%20sorting)
|
||||
* [Examples](https://publish.obsidian.md/tasks/Queries/Sorting#Examples)
|
||||
|
||||
## Basics
|
||||
|
||||
To sort the results of a query different from the default, you must add at least one `sort by` line to the query.
|
||||
|
||||
## Sort by Task Statuses
|
||||
|
||||
For more information, including adding your own customised statuses, see [Statuses](https://publish.obsidian.md/tasks/Getting+Started/Statuses).
|
||||
|
||||
### Status
|
||||
|
||||
* `sort by status` (done or todo)
|
||||
|
||||
### Status Name
|
||||
|
||||
* `sort by status.name` (Done, Todo, Cancelled, In Progress, Unknown, My very important custom status, etc - sorted alphabetically)
|
||||
|
||||
`sort by status.name` was introduced in Tasks 1.23.0.
|
||||
|
||||
### Status Type
|
||||
|
||||
* `sort by status.type` (Sorted in the order `IN_PROGRESS`, `TODO`, `DONE`, `CANCELLED` then `NON_TASK`)
|
||||
|
||||
`sort by status.type` was introduced in Tasks 1.23.0.
|
||||
|
||||
## Sort by Dates in Tasks
|
||||
|
||||
### Done Date
|
||||
|
||||
* `sort by done` (the date when the task was done)
|
||||
|
||||
### Due Date
|
||||
|
||||
* `sort by due` (the date when the task is due)
|
||||
|
||||
### Scheduled Date
|
||||
|
||||
* `sort by scheduled` (the date when the task is scheduled)
|
||||
|
||||
### Start Date
|
||||
|
||||
* `sort by start` (the date when the task starts)
|
||||
|
||||
* `sort by created` (the date when the task was created)
|
||||
|
||||
`sort by created` was introduced in Tasks 2.0.0.
|
||||
|
||||
### Happens
|
||||
|
||||
* `sort by happens` (the earliest of start date, scheduled date, and due date)
|
||||
|
||||
`sort by happens` was introduced in Tasks 1.21.0.
|
||||
|
||||
## Sort by Other Task Properties
|
||||
|
||||
### Description
|
||||
|
||||
* `sort by description` (the description of the task)
|
||||
|
||||
### Priority
|
||||
|
||||
* `sort by priority` (priority of the task; "low" is below "none": [priorities](https://publish.obsidian.md/tasks/Getting+Started/Priority))
|
||||
|
||||
### Urgency
|
||||
|
||||
* `sort by urgency` ([urgency](https://publish.obsidian.md/tasks/Advanced/Urgency))
|
||||
|
||||
### Recurrence
|
||||
|
||||
* `sort by recurring` (recurring tasks sort before non-recurring ones: [Recurring Tasks](https://publish.obsidian.md/tasks/Getting+Started/Recurring+Tasks))
|
||||
|
||||
### Tags
|
||||
|
||||
* `sort by tag` (the description of the task)
|
||||
|
||||
If you want to sort by tags, by default it will sort by the first tag found in the description. If you want to sort by a tag that comes after that then you can specify the index at the end of the query. All tasks should have the same amount of tags for optimal sorting and the tags in the same order. The index starts from 1 which is also the default.
|
||||
|
||||
For example this query will sort by the second tag found in the description.
|
||||
|
||||
```autohotkey
|
||||
```tasks
|
||||
sort by tag 2
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Tag sorting was introduced in Tasks 1.6.0.
|
||||
|
||||
## Sort by File Properties
|
||||
|
||||
### File Path
|
||||
|
||||
* `sort by path` (the path to the file that contains the task)
|
||||
|
||||
### Root
|
||||
|
||||
It is not currently possible to sort by the top-level folder that contains the task.
|
||||
|
||||
### Folder
|
||||
|
||||
It is not currently possible to sort by the folder that contains the task.
|
||||
|
||||
### File Name
|
||||
|
||||
* `sort by filename` (the filename of the file that contains the task, with its extension)
|
||||
* Note that tasks from different notes with the same file name will be sorter.
|
||||
|
||||
`sort by filename` was introduced in Tasks 1.21.0.
|
||||
|
||||
### Heading
|
||||
|
||||
* `sort by sort by heading` (the heading preceding the task; files with empty headings sort before other tasks)
|
||||
|
||||
`sort by heading` was introduced in Tasks 1.21.0.
|
||||
|
||||
## Multiple sort criteria
|
||||
|
||||
You can add multiple `sort by` query options, each on an extra line. The first sort has the highest priority. Each subsequent `sort` will sort within the existing sorting.
|
||||
|
||||
## Notes
|
||||
|
||||
If you want tasks to be sorted the way they were sorted before urgency was introduced, add the following `sort` expressions to your queries:
|
||||
|
||||
```xquery
|
||||
```tasks
|
||||
sort by status
|
||||
sort by due
|
||||
sort by path
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Sorting by description should take into account `[[Links]]` and `[Links with an|Alias]` (note pipe). It should also take into account `*italics*` and `==highlights==`. It sorts by the text that's visible in preview mode.
|
||||
|
||||
## Reverse sorting
|
||||
|
||||
After the name of the property that you want to sort by, you can add the `reverse` keyword. If given, the sort order will be reverse for that property.
|
||||
|
||||
Note that `reverse` will reverse the entire result set. For example, when you `sort by done reverse` and your query results contain tasks that do not have a done date, then those tasks without a done date will be listed first.
|
||||
|
||||
## Examples
|
||||
|
||||
```xquery
|
||||
```tasks
|
||||
not done
|
||||
due today
|
||||
sort by due
|
||||
```
|
||||
|
||||
```tasks
|
||||
done
|
||||
sort by done reverse
|
||||
```
|
||||
|
||||
```tasks
|
||||
not done
|
||||
due before next monday
|
||||
sort by status
|
||||
sort by description reverse
|
||||
sort by path
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Sorting
|
||||
Reference in New Issue
Block a user