Skip to content

Testing Bases Tools

Tools: list_bases, get_base, query_base

Note: Obsidian Bases is a feature that creates dynamic views of notes based on filters. The .base file is a YAML configuration that defines which notes to include. The actual data comes from notes in the vault that match the filters.

How Obsidian Bases Work

A .base file defines:

  • filters: Rules to select which notes to include (e.g., by tag, folder, or property)
  • properties: How to display note properties with custom display names
  • formulas: Calculated fields (e.g., age from birthday)
  • views: Table/card layouts and sorting

The data is NOT stored in the .base file - it comes from matching notes in your vault.


Test 1: List All Bases

List all database files (bases) in the vault

Expected: Returns list of .base files with names and paths.


Test 2: Get Base Structure and Data

Get the structure and content of "People.base" (or any base that exists)

Expected: Returns the base configuration, columns (from config properties), and rows (from matching notes).


Test 3: Create a Test Base

First, create some notes with tags:

Create a note "People/John Doe.md" with:
- tags: ["people"]
- birthday: 1990-05-15
- Content: "# John Doe\n\nA person note."
Create a note "People/Jane Smith.md" with:
- tags: ["people", "vip"]
- birthday: 1985-10-20
- Content: "# Jane Smith\n\nAnother person."

Then create a base file manually in your vault at Bases/People.base:

yaml
filters:
  and:
    - note.tags.contains("people")
properties:
  file.name:
    displayName: Name
  note.tags:
    displayName: Tags
  note.birthday:
    displayName: Birthday
formulas:
  Age: (now() - birthday).years.floor()

Test 4: Query Base (All Records)

Get all records from "Bases/People.base"

Expected: Returns all notes that have the tag "people".


Test 5: Query Base with Filter

Query "Bases/People.base" and filter for records where file.name = "John Doe"

Expected: Returns only John Doe's record.


Test 6: Query Base with Sort

Query "Bases/People.base" and sort by "birthday" in descending order

Expected: Returns rows sorted by birthday (most recent first).


Test 7: Query Base with Limit

Get the first 1 record from "Bases/People.base"

Expected: Returns at most 1 row.


Test 8: Formula Evaluation

Get "Bases/People.base" and check if the Age formula is calculated

Expected: Each person should have a formula.Age value calculated from their birthday.


Full Flow Test

Test bases functionality:
1. List all bases in the vault
2. If a base exists, get its full structure and content
3. Check the columns (from config properties)
4. Query the base without filters to see all matching notes
5. Query with an additional filter on one of the columns
6. Query with sorting on a column
7. Query with a limit of 1 record

Expression Parser

The bases parser includes a full expression parser that supports complex filter expressions and formulas.

Operators

OperatorDescriptionExample
==, =Equalitystatus == "active"
!=Inequalitystatus != "done"
>Greater thanpriority > 5
>=Greater than or equalpriority >= 5
<Less thanpriority < 3
<=Less than or equalpriority <= 3
&&, andLogical ANDstatus == "active" && priority > 3
||, orLogical ORstatus == "done" || status == "cancelled"
!, notLogical NOT!file.name.contains("Template")
+Addition / Concatenationprice + tax, "Hello " + name
-Subtractiontotal - discount
*Multiplicationquantity * price
/Divisiontotal / count
%Moduloindex % 2

Supported Filter Types

Basic Filters

Filter PatternDescriptionExample
note.tags.contains("tag")Notes with a specific tagnote.tags.contains("people")
file.name.contains("text")Notes with text in filenamefile.name.contains("Template")
file.folder.contains("path")Notes in a specific folderfile.folder.contains("Projects")
!filterNegation (NOT)!file.name.contains("Template")

Advanced Filters (Expression Parser)

Filter PatternDescriptionExample
property == valueProperty equals valuestatus == "active"
property != valueProperty not equalsstatus != "done"
property > valueComparisonpriority > 3
file.hasTag("tag")Check if file has tagfile.hasTag("project")
file.inFolder("path")Check if in folderfile.inFolder("Projects")
file.hasProperty("name")Check if has propertyfile.hasProperty("status")
file.hasLink("path")Check if links to filefile.hasLink("Index.md")
file.mtime > now() - "7d"Date comparisonModified in last 7 days

Filters can be combined with:

  • and: All conditions must match
  • or: Any condition can match

File Properties

The following file properties are available in filters and formulas:

PropertyTypeDescription
file.namestringFile name without extension
file.pathstringRelative path from vault root
file.folderstringParent folder path
file.extstringFile extension (without dot)
file.basenamestringFile name without path or extension
file.sizenumberFile size in bytes
file.ctimeDateCreation time
file.mtimeDateLast modification time
file.tagsListTags from frontmatter and content
file.linksListOutgoing wiki links
file.embedsListEmbedded content references

Global Functions

FunctionDescriptionExample
now()Current date/timenow()
today()Today at midnighttoday()
date("string")Parse date stringdate("2024-01-15")
if(cond, true, false)Conditionalif(status == "done", "Complete", "Pending")
min(...values)Minimum valuemin(1, 2, 3)
max(...values)Maximum valuemax(1, 2, 3)
number(value)Convert to numbernumber("42")
list(...values)Create listlist(1, 2, 3)
link(path, display?)Create linklink("note.md", "My Note")
duration("string")Parse durationduration("7d")

Date Arithmetic

Duration Units

UnitAliases
Yearsy, year, years
MonthsM, month, months
Weeksw, week, weeks
Daysd, day, days
Hoursh, hour, hours
Minutesm, min, minute, minutes
Secondss, sec, second, seconds

Date Operations

OperationDescriptionExample
date + "duration"Add durationtoday() + "7d"
date - "duration"Subtract durationnow() - "1M"
date1 - date2Difference (ms)now() - file.ctime
(diff).yearsConvert ms to years(now() - birthday).years
(diff).daysConvert ms to days(now() - file.mtime).days

Date Functions

Function/PropertyDescriptionExample
date.yearYear (4 digits)birthday.year
date.monthMonth (1-12)birthday.month
date.dayDay of monthbirthday.day
date.hourHour (0-23)file.mtime.hour
date.minuteMinute (0-59)file.mtime.minute
date.secondSecond (0-59)file.mtime.second
date.format("pattern")Format datebirthday.format("YYYY-MM-DD")
date.relative()Relative timefile.mtime.relative() → "3 days ago"
date.date()Date without timenow().date()
date.time()Time stringnow().time() → "14:30:45"

String Functions

FunctionDescriptionExample
str.contains("value")Contains substringname.contains("John")
str.containsAll("a", "b")Contains allname.containsAll("John", "Doe")
str.containsAny("a", "b")Contains anystatus.containsAny("done", "complete")
str.startsWith("prefix")Starts withname.startsWith("Dr.")
str.endsWith("suffix")Ends withfile.name.endsWith("_draft")
str.lower()Lowercasename.lower()
str.upper()Uppercasename.upper()
str.title()Title casename.title()
str.trim()Remove whitespacename.trim()
str.replace("a", "b")Replace textstatus.replace("_", " ")
str.split(",")Split to listtags.split(",")
str.slice(start, end)Substringname.slice(0, 10)
str.lengthString lengthname.length
str.isEmpty()Check if emptydescription.isEmpty()

Number Functions

FunctionDescriptionExample
num.abs()Absolute value(-5).abs() → 5
num.ceil()Round up(4.2).ceil() → 5
num.floor()Round down(4.8).floor() → 4
num.round(digits?)Round(4.567).round(2) → 4.57
num.toFixed(digits)Format decimal(4.5).toFixed(2) → "4.50"

List Functions

FunctionDescriptionExample
list.contains(value)Contains elementtags.contains("important")
list.containsAll(a, b)Contains alltags.containsAll("a", "b")
list.containsAny(a, b)Contains anytags.containsAny("urgent", "high")
list.join(",")Join to stringtags.join(", ")
list.sort()Sort listtags.sort()
list.reverse()Reverse listitems.reverse()
list.unique()Remove duplicatestags.unique()
list.flat()Flatten nestednested.flat()
list.slice(start, end)Slice listitems.slice(0, 5)
list.first()First elementtags.first()
list.last()Last elementtags.last()
list.lengthList lengthtags.length
list.isEmpty()Check if emptytags.isEmpty()

Any Type Functions

FunctionDescriptionExample
value.toString()Convert to string(42).toString()
value.isTruthy()Check if truthystatus.isTruthy()
value.isType("type")Check typevalue.isType("string")

Type names: string, number, boolean, date, list, array, object, null, undefined, link, regex, file, image, icon, html


FunctionDescriptionExample
link.asFile()Convert link to File objectmyLink.asFile()
link.linksTo(file)Check if link points to filemyLink.linksTo("note.md")

Object Functions

FunctionDescriptionExample
object.isEmpty()Check if object is emptyobj.isEmpty()
object.keys()Get list of keysobj.keys()
object.values()Get list of valuesobj.values()
object.entries()Get list of [key, value] pairsobj.entries()
object.hasKey(key)Check if object has keyobj.hasKey("status")

Regular Expressions

Regular expressions can be used in filters and formulas:

/pattern/flags.matches(value)
MethodDescriptionExample
matches(value)Test if value matches pattern/hello/.matches("hello world")
test(value)Alias for matches/\\d+/.test("abc123")
exec(value)Execute and return match array/hello/.exec("hello world")

Flags: g (global), i (case-insensitive), m (multiline), s (dotall), u (unicode), y (sticky)


this Object

The this keyword provides context about the current file:

yaml
# In a base filter, use this to reference the embedding file
filters:
  and:
    - 'file.hasLink(this.file)'  # Find notes that link to the current file

The this object changes based on context:

  • When base is opened directly: this.file = the .base file
  • When base is embedded: this.file = the file containing the embed
  • When base is in sidebar: this.file = the currently active file

Advanced Functions

FunctionDescriptionExample
file(path)Create File object from pathfile("folder/note.md")
image(path)Create Image object for renderingimage("path/to/img.png")
icon(name)Create Icon object (Lucide icons)icon("star")
html(content)Create HTML object for renderinghtml("<b>bold</b>")
escapeHTML(str)Escape HTML special charactersescapeHTML("<script>")

Supported Formula Types

Formulas can use any expression with the full expression parser:

yaml
formulas:
  Age: (now() - birthday).years.floor()
  DaysSinceModified: (now() - file.mtime).days.floor()
  FullName: firstName + " " + lastName
  IsOverdue: due_date < today()
  Priority: if(urgent, "High", "Normal")
  TagCount: tags.length

Column Types

Detected column types include:

  • text - String values
  • number - Numeric values
  • checkbox - Boolean values
  • date - Date strings (YYYY-MM-DD) or Date objects
  • url - HTTP/HTTPS URLs
  • multi-select - Array values
  • formula - Calculated fields

Summaries (Aggregations)

Summaries allow you to aggregate column values. Add a summaries section to your base config:

yaml
summaries:
  price: Average
  quantity: Sum
  due_date: Earliest

Built-in Summary Types

SummaryInput TypeDescription
AverageNumberMean of all values
MinNumberSmallest value
MaxNumberLargest value
SumNumberTotal of all values
RangeNumberMax - Min
MedianNumberMiddle value
StddevNumberStandard deviation
EarliestDateOldest date
LatestDateMost recent date
CheckedBooleanCount of true values
UncheckedBooleanCount of false values
CountAnyTotal number of values
EmptyAnyCount of empty values
FilledAnyCount of non-empty values
UniqueAnyCount of unique values

Custom Summaries

You can use expressions for custom aggregations:

yaml
summaries:
  price: 'values.filter(v => v > 0).length'

Views Configuration

Views define how data is displayed. You can have multiple views per base:

yaml
views:
  - type: table
    name: "Active Tasks"
    limit: 10
    filters:
      and:
        - 'status != "done"'
    sort:
      - property: priority
        direction: DESC
      - property: due_date
        direction: ASC
    groupBy:
      property: status
      direction: ASC
    summaries:
      priority: Average

View Properties

PropertyTypeDescription
typestringView type: table, cards, list, map
namestringDisplay name for the view
limitnumberMaximum rows to show
filtersobjectAdditional filters (same syntax as base filters)
orderstring[]Column display order
sortarraySort configuration
groupByobjectGroup rows by property
summariesobjectView-specific summaries

Sort Configuration

yaml
sort:
  - property: column_name
    direction: ASC   # or DESC

GroupBy Configuration

yaml
groupBy:
  property: status
  direction: ASC   # or DESC

Released under the MIT License.