Overview
As we all know, implementing a “database”-like requirement in Obsidian has always been a pain point.
Although it can be achieved with plugins, it often requires creating a separate page for each piece of data… which is quite troublesome and not as comfortable and seamless as Notion.
A long time ago, I had an idea:
What if I have a note specifically for collecting content on a certain topic and I want to turn it into a “mini-database”—not requiring editing, just summarizing and displaying specific attributes of the various contents inside, is that possible?
This question troubled me for half a year, and finally, recently, with my learning of OB and the Dataview plugin, I realized this long-standing need.
Display
Effect demonstration:
As you can see, a “lightweight database” can be automatically generated through multiple headings within the note.
Supported features:
- Clicking on the title can directly jump to the corresponding content.
- A database can be created with just one note.
- Supports combinations of multiple attributes.
- Automatically generates table columns based on metadata.
- (Generally) updates in real-time, depending on the refresh interval of Dataview.
- Simple and easy to use: only three lines of code plus a JS script file are needed to implement it.
Working Principle
Writing the Note
You need to use the Dataview plugin and a fixed format:
## Title
[Attribute::Value] [Attribute2::Another Value]
- The metadata line should be written right next to the title line (the heading level is not restricted—any number of hashtags is fine).
- Multiple metadata can be included using the format
[key::value]
, and multiple attributes in one line must be separated by 2 spaces.
- The same attribute (e.g.,
Tags
) can have multiple values written in one inline attribute separated by commas, or multiple same-name attributes in one line (which will be automatically merged).- First method:
[Tags:Obsidian,css]
- Second method:
[Tags:Obsidian] [Tags:css]
- First method:
[!Info] About Inline Attributes
For more details, see the Dataview documentation: Adding Metadata - Dataview
Presenting the Database
First, open the settings of the Dataview plugin and ensure that these options are enabled:
Then, you need to place this JS file in your note library, named liteDatabase.js
:
const useList = false;
const curNote = dv.current();
if (!curNote){
dv.span("The current document is not loaded, please reopen it.");
return;
}
let tarFile = await app.vault.getAbstractFileByPath(curNote.file.path);
// Get the meta data of the current file
const curFileMeta = app.metadataCache.getFileCache(tarFile);
const headings = curFileMeta.headings;
const headingsList = headings.map(k => k.heading)
// Get the text content of the current article
const curFilePath = curNote.file.path;
const curTFile = await app.vault.getFileByPath(curFilePath)
const content = await app.vault.cachedRead(curTFile);
if (!headings) {
dv.span("The current document lacks titles.");
return;
}
const meta = content.matchAll(/#+ (.*)\n(\[.*\:.*\])/gm);
// Use titles as keys and metadata as values to create a DV table
let tableHeads = ["Title"]
// Store as a dictionary first
let metaValues = []
if (meta) {
for (let m of meta) {
let title = m[1]
// Check if the title is in the headings (to avoid treating content in code blocks as metadata)
if (headingsList.indexOf(title) == -1) {
continue
}
let metaList = m[2].split(" ")
let metaDict = {}
// Add metadata keys to the table header
for (let i = 0; i < metaList.length; i++) {
let keyValue = metaList[i].replace("[", "").replace("]", "").split("::")
// console.log(metaList[i], keyValue)
let key = keyValue[0].trim()
if (tableHeads.indexOf(key) == -1) {
tableHeads.push(key)
}
if (useList){
// 1. List format, duplicate attributes will be merged
let value = [keyValue[1]]
metaDict[key] = metaDict[key] ? metaDict[key].concat(value) : value
} else {
// 2. Text format, duplicate attributes will use the latest
let value = keyValue[1]
metaDict[key] = metaDict[key] ? metaDict[key] + `,${value}` : value
}
}
let returnValuesList = []
for (let i = 0; i < tableHeads.length; i++) {
if (i == 0) {
returnValuesList.push(`[[#${m[1]}]]`)
} else {
returnValuesList.push(metaDict[tableHeads[i]] ? metaDict[tableHeads[i]] : "")
}
}
metaValues.push(returnValuesList)
}
}
dv.table(
tableHeads,
metaValues.map(k => k)
)
You can also view or download this code file directly on GitHub Gist: DVJS Code - Lite Database for Obsidian
(Any updates will be uploaded directly to Gist later)
Then, insert the following into your note:
```dataviewjs
dv.view("liteDatabase")
```
If the note writing follows the rules, you should now be able to see the presentation of the lightweight database!
Test Text
If you haven’t written any content yet, you can also directly copy this content into the note to see the effect:
## Undertale
[English Name::Undertale] [Tags::Touching, Story-driven]
"You fell into the underground, and—"
A story about friendship.
## Outer Wilds
[English Name::Outer Wilds] [Tags::Exploration, Touching]
"Hey, have you ever tried falling into a black hole?"
A story about exploration.
## BioShock Infinite
[Tags::Fun] [Tags::Touching, Story-driven] [English Name::BioShock Infinite]
"For how many years, I am still by your side."
A story about time.
Expansion
Since it uses JS language, theoretically, there is great potential for expansion in both form and content.
For example, you can also use your own defined format instead of Dataview inline attributes.
Or you might want to further process the retrieved metadata…
By modifying the JS file (or having GPT help you modify it), you can customize it in the way you want!