Parsing delimited YAML Frontmatter with DataViewJS -- help / just bad idea?

I sure could use the Community’s help migrating queries from Dataview to DataviewJS. I’ve built an extremely fast and reliable project management system based on semicolon-delimited ( ; ) entries in YAML frontmatter (basic but effective). I can quickly record multiple fields of information in bullets and parse it for filtering and display. For example, a to-do entry including task, priority, vendor, and context looks like this:

- Fix basement leak; 1; ProBrickLLC; Site
- Order doors; 2; Me; Task
- ...

The Dataview ‘split’ function makes it easy to parse the strings into fields:

	split(EntryToDo,"; ")[0] AS "Task",
	split(EntryToDo,"; ")[1] AS Pri
FROM "Projects"
WHERE ((NoteType = "ProjPhase"
	AND contains(ProjID, this.file.frontmatter.ProjID)
	 AND EntryToDo)
	 AND (split(EntryToDo,"; ")[2] = "Site")

And generate a pretty table:


For a variety of reasons I want to create the tables usings DataViewJS instead of DataView Despite lots of Googling and Redditing, I can’t find an equivalent split command for DataviewJS.

Am I missing something? How tenuous and limiting is this structure? The system is fast and clean, so I’d rather not move to a key-value approach that forces me to type all the keys every time I want to enter the values–yes I could automate with Metadata Menu and Quick Add–but I have LOTS of entires, I often enter data on an iPhone, and I don’t want all the repetitive text and voluminous indentations that come with key:value pairs gumming up my clean notes.

Can someone offer a recipe for parsing with JS? Is there a fancy command to make my life easy…or will I need a sub routine to iterate each bullet, add values to an array, etc.?

I’m happy to share back my project management system, which I used to manage a residential construction portfolio with multiple whole-house rebuilds, renovations, and smaller jobs.

thanks, Josh

Here is one option to match that query of yours, and hopefully it’ll also allow you to understand how to build similar queries:

console.log("\n\n New run, 2nd query")

const result = dv.pages('"Projects"')
  .where(p => p.NoteType == "ProjPhase" &&
    dv.current().ProjId in p.ProjId &&
    p.EntryToDo )
  .flatMap(p => {
    const result = []
    p.EntryToDo.forEach(e => {
     const newRow = { ...p } // Make a copy of the current row

     // Extend with the values from this entry of EntryToDo
     const [task, priority, vendor, context] = e.split(/\s*;\s*/)
     newRow.task = task
     newRow.priority = priority
     newRow.vendor = vendor
     newRow.context = context

     // Push the new row onto the result list
    return result
  .where( p => p.context == "Site" )

 dv.table(["Task", "Pri", "Link"], m=> [m.task, m.priority,] ))

There’s a few tricks in this query:

  • flatMap() is used to expand a row into multiple rows. In this case to split each file into separate rows with all the previous information and information from each EntryToDo in separate rows
  • p.EntryToDo.forEach() – Just some syntactic sugar to loop through each entry of the list
  • const newRow = { ...p } – This starts of the new row with all the information from the previous row
  • const [ a, b, c ] = ... – This allows the split to go directly into named variables. In this case we could have lived with them being an array, and then assigned array indexed values to the properties in the next lines, but …
  • e.split(/\s*;\s*/) – I changed to a regex split in order to eliminate any extra whitespace surrounding the semi-colon, ;
  • I’m using two .where() in your case, and that’s just because I wanted to use the first where clause to limit the rows on which we try to expand the EntryToDo, and then we’ve got that information we could do the final where clause on the context and not the vendor as you indicated in your query with [2] ???

Hopefully that’s enough explanations to what’s happening. If not feel free to ask, and I shall try to confuse you a little more (or something like that). :smiley:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.