Add Field in 2600 existing Files

Hello

I am looking for a way to insert the first 8 characters from the file name as inline variable in about 2600 files.

With quickadd I can insert one by one

Created:: [[<% tp.file.title.slice (0,8) %>]]

Is that possible with Templater?

1 Like

Moved from Developers & API to Help (and added Templater tag).

1 Like

Yes, it’s possible. But be very wary of what you do, and whether you actually want to do this. And if possible, please do take a backup before proceeding.

A Templater script to change frontmatter
<%*
function trDebug(msg, eol="\n", log=false) {
 if (log)
   console.log(msg)
   
 tR += msg + eol
}

function modifyFrontmatter(fm, suggestion) {
  // Change next line to 'false' (instead of 'true') if 
  // you don't want to check for existing key
  const checkKeyExistence = true
  
  const myKey = "Created"
  
  if (checkKeyExistence) {
    const lowercaseKeys = obj =>
      Object.keys(obj).reduce((acc, key) => {
        acc[key.toLowerCase()] = key;
        return acc;
      }, {})
    const allKeys = lowercaseKeys(fm) 
    console.log(allKeys)
    if ( allKeys.hasOwnProperty(myKey.toLowerCase()) ) {
      trDebug(`Key already exists: "${ allKeys[myKey.toLowerCase()] }"`, " | ")
      return  // Bail out if key already exists
    }
  }  
  
  // Don't add it if the suggestion is empty, or doesn't match
  // the YYYY-MM-DD date format
  if (!suggestion || !suggestion.match(/[0-9]{4}-[0-1][0-9]-[0-3][0-9]/)) {
    trDebug(`Not a date "${ suggestion }"`, " | ")
    return  // Bail out if not a YYYY-MM-DD date
  }

  // Add the field to the frontmatter
  trDebug(`Setting "${ myKey }: ${ suggestion }"`, " | ")
  fm[myKey] = suggestion
}

/***********************************************************/
/* Change to give you the list of files you want to change */
/***********************************************************/
const filenames = DataviewAPI.pages('"ForumStuff/f50968"').file.name

trDebug(`\n\nScript ${ tp.config.template_file.name } starts at ${tp.date.now("YYYY-MM-DD HH:mm")}`, "\n", true)
trDebug(`Will change frontmatter in ${ filenames.length } files`) 

/***********************************************************/
/* Please verify that the filenames list is OK, before     */
/* changing the next line to 'true' (not 'false'), which   */
/* triggers the actual change of the frontmatter           */
/***********************************************************/
const changeFrontmatter = false

for (let name of filenames) {
  trDebug(` ${ name }`, " | ")

  if ( changeFrontmatter ) {
    const theFile = await tp.file.find_tfile(name)
    await app.fileManager.processFrontMatter(theFile, (fm) => modifyFrontmatter(fm, name.slice(0, 10)) )
  }
  trDebug("done")
}
%>

Some comments regarding this scripts, please read carefully:

  • There is a variable, checkKeyExistence, set to true, which enforces that the script doesn’t change the frontmatter if the key already exists, I strongly suggest to leave that as is. If it encounters a file where the key exists, it bails out.
  • Change the filenames query, close to the middle of the script, and run the insert template function for a dry run to verify that you’re targetting the correct number of files. Only after this, change the changeFrontmatter to be true.
  • I’d also suggest to make the query to that it doesn’t include files which are not to be changed (or files which have already been changed). I’ve written tests to avoid these to be changed (see keyExistence stuff above), but better safe than sorry, in case something should go wrong
  • You said slice(0, 8), that doesn’t match a legal date of YYYY-MM-DD, which I’m assuming you’d want to insert into the Created field. To get that you need to have slice(0, 10). In the code I’ve changed this, and I’ve also inserted a check that this suggestion (or slice) actually matches the date format. It bails out, with an error message, if the file name doesn’t match this format

When you insert this template, it’ll produce a lot of debug output into the current document, so I suggest creating some variant of a log note, to keep track of what’s happening. When debugging and testing this template, I assigned it to a hotkey, but it should work just the same by doing the command palette and/or Templater: Open Insert Template modal.

I’ve run this query on a smaller set of files, and it works in the cases I’ve thrown at it, that includes the following cases:

  • Files not matching the the date format
  • Files already having the key (in various lower-/uppercase variants)
  • Files with no frontmatter at all

Finally, I’ll repeat what I said at the start, please do take a backup before proceeding, and even though I’ve tried to write the template as robust as possible, you do proceed at your own risk.

2 Likes

Thanks for the extensive help. I should be able to get on with it.
The current files still have the format “YYYYMMDD_Title”.
Therefore Slice(0,8)

I would then strongly suggest to switch date format, to make future queries a lot easier.

Yes, this date format is what prompted the year change conversion in my system.
In Obsidian this is surprisingly more elaborate than in DevonThink or Photo Management. Date is the common key. Because Obsidian has slowly become my central PKM, the effort is justified.