[[DataView]] is a great plugin but it, like other plugins, will not work with [[Obsidian Publish]]. However, there is a work around. I first found this work around on [this blog](https://joschua.io/posts/2023/09/01/obsidian-publish-dataview/) (there's a helpful expansion on this [published repository](https://obsidianttrpgtutorials.com/Obsidian+TTRPG+Tutorials/Plugin+Tutorials/Dataview/Dataview+-+Obsidian+Publish) as well).
I use this technique for my [[book shelf]] and [[literature]] hubs. Because I publish my notes, I try to limit the use of DataView elsewhere, but it's too powerful to be avoided everywhere!
For this solution, you will need the community plugins DataView and [[Templater]]. We will create a template that will run [[JavaScript]] code to replace the existing notes with new notes that contain the output of our DataView query. Advanced users may review the Obsidian docs (see especially the section [Vault](https://docs.obsidian.md/Plugins/Vault)) for other ways of interacting with files.
> [!Warning]
> This process replaces the existing note(s) entirely, so any changes made to the note after running this will be blown away when you re-run it!
Let me introduce a simple script here with the main logic before we put it all together. This code first accesses the DataView API, defines a file to overwrite, defines a DataView query, and then writes the result of the query to the specified file.
```javascript
// Access DataView plugin API
const dv = app.plugins.plugins["dataview"].api;
// Define file to be overwritten
const filename = "Bookshelf";
const tFile = tp.file.find_tfile(filename);
// Define query as normal DataView query
const query = `
TABLE WITHOUT ID
"" as Cover,
link(file.link, title) as Title,
last-read as "Last Read"
FROM "lit/books"
WHERE last-read
SORT last-read DESC`
// Get query results
await dv.queryMarkdown(query);
// write query output to file
await app.vault.modify(tFile, queryOutput.value);
```
> [!Tip]
> Get the query working in a simple DataView query in the note first before trying to write the full script in a Templater template.
We can extend this code to support multiple queries in multiple files. Note we use `Map()` which creates an ordered dictionary in JavaScript.
```JavaScript
// Define all files and queries
const fileAndQuery = new Map([
[
"Bookshelf",
bookshelf_query
],
[
"Literature"
literature_query
],
])
await fileAndQuery.forEach(async (query, filename) => {
// Create new file if not exists
if (!tp.file.find_tfile(filename)) {
await tp.file.create_new("", filename);
new Notice(`Created ${filename}.`);
}
// Get file and contents
const tFile = tp.file.find_tfile(filename);
const queryOutput = await dv.queryMarkdown(query);
const fileContent = `%% update via "Update Publish Files" template %% \n\n${queryOutput.value}`;
// Update file with query results
try {
await app.vault.modify(tFile, fileContent);
new Notice(`Updated ${tFile.basename}.`);
} catch (error) {
new Notice("⚠️ ERROR updating! Check console. Skipped file: " + filename , 0);
}
});
}
```
Finally, we can open the Obsidian Publish panel whenever we run this by appending
```JavaScript
app.commands.commands["publish:view-changes"].callback;
```
For my literature hub, I actually need to run multiple queries and I'd like them to be organized under headings. That will require extending this method slightly further. See the [[update publish files]] template for full code.