Delete custom metadata fields

Hi,

is it right that when I delete a custom metadata field, the metadata still remain within the documents / the database ?
If this is the desired behavior then

  • how can I have an overview of the lost metadata that could be reactivated ?
  • why should I be even able to delete a md field. When reusing the same field later you can run into conflicts?

regards
Andreas

Deleting a definition does not delete metadata, e.g. different users/computers could use different setups. However, there’s no such overview available.

I have been experimenting with custom metadata and have just settled on a set of fields and types. I have deleted the experimental metadata fields that are no longer needed. In my case, there is no one else accessing the data and I would like to remove the “orphaned” metadata from the items in my databases. Is there any way to remove this data that was generated during my testing.

I am happy to do this via a script. I just need to know where to find the data.

Editing the metadata of these items again will remove the now obsolete data.

I’m not sure that I made myself clear.

I understand that custom meta data values will be over written by subsequent editing. However, I am trying to remove the obsolete keys from key/value pairs that comprise the custom meta data, not just any obsolete values.

For example I have an RTF custom meta data field (Backlinks) that I no longer need. I would like to remove “Backlinks” from the custom meta data of all my databases.

I can see all of this metadata from my script, and I know the names of the old “keys”, I just want to know how to safely remove them.

Thanks!

This is not a full fix unless you were only use a text datatype on your custom metadata. Other datatypes may be set to a zero’d value, like $0.00.

property attributesToScrub : {"Price", "Tax", "Location", "Digital Object Identifier", "Barcode", "Total"}

tell application id "DNtp"
	repeat with theRecord in (selection as list)
		repeat with thisAttribute in attributesToScrub
			set mdQuery to (get custom meta data for thisAttribute from theRecord)
			if mdQuery ≠ missing value then
				add custom meta data "" for thisAttribute to theRecord
			end if
		end repeat
	end repeat
end tell

Removing it completely would be something @cgrunenberg would have to assess.

Thanks Jim

I can do that. BTW what would be the format for an empty item-link?

It’s my own fault … I missed the fact that custom metadata was global and couldn’t be removed just like tags so I created a bit of a mess in my test database that has polluted far and wide.

If there is away to simply remove all custom metadata, then I would be ok with that since I have a script to generate the custom meta data that I am planning on using moving forward.

Interestingly if I run the script against an RTF formatted custom meta data field, then the text disappears from the custom info panel, but a large chunk of RTF data remains in the custom meta data record.

Alternatively, if I manually delete the RTF text from the info panel then it is removed from the info panel but - more interestingly - also completely removed from the custom meta data record. When I go to check the meta data after removing it in this way from the panel, then I get a missing value.

Not specific to RTF. If I manually remove a link from the info panel by setting it to “No Item” then the custom data changes to << empty >>. In other words manually removing custom meta data from the UI actually removes the key/value pair from the record, it does not just set the value to a 0/null/"" value, the key is gone (for that record).

This is what I’m seeing when running it, including Rich Text and Link datatypes…

As I said, @cgrunenberg would have to weigh in on this .

There’s no remove custom meta data for thisAttribute from theRecord command (but perhaps there could be?)

Thanks again Jim.

I think a “remove” custom meta data command would be extremely useful. Perhaps even with the ability to not only specify a single (known) attribute, but all of them in one go. Just while we are dreaming …


Back to your log - I’m curious what you see if you do a
get custom meta data for “Rich Text” from content id …

after setting the meta data to “”

I am also getting a true return value, but there is custom styling info left behind in my case.

Back to your log - I’m curious what you see if you do a
get custom meta data for “Rich Text” from content id …

after setting the meta data to “”

same here - thanks!

Interestingly, there is some vestigial RTF data with my method, as you’ve seen.

image

exactly!

For anyone else running into this issue I would note the following temporary workaround for removing this “orphaned” RTF data and the custom meta data field from a record.

  1. manually add any text via the info panel to the RTF custom meta data field
  2. then manually remove that data, again from the info panel

The result (for me) is that the (key/value) pair for this custom meta data field are completely removed from that record.

In my case, I have identified the records that need to be “repaired” via a script and can now do that manually using this method.

I still like the idea of programmatically being able to remove custom meta data @cgrunenberg :wink:

This is actually possible but not in case of rich text due to limitations of AppleScript.

With the scripting addition List & Record Tools (from one of the Script Debugger developers) it’s possible to delete items in an AppleScript record. Setting a record’s metadata to this changed AppleScript record works (didn’t test with rich text, but it should work too, I think).

My idea now is to delete unwanted metadata from all records in all databases in order to completely remove it from DEVONthink. Would this be sufficient? Is metadata automatically removed from CustomMetaData.plist if there’s no single record that uses it anymore? I really want to get completely rid of it.

At least as long as there’s no rich text custom metadata it should be sufficient.

No, the definitions won’t change.

Done!

Here are the scripts I used.

The first is an utility script that copies meta data identifiers from DEVONthink’s plist.

Script: Copy Custom Meta Data Identifiers from plist
-- Copy Custom Meta Data Identifiers from plist

property sortIdentifiers : true
property thePlistPath : POSIX path of (path to application support from user domain) & "DEVONthink 3/CustomMetaData.plist"

tell application "System Events"
	try
		set theIdentifieres to {}
		tell property list file thePlistPath
			repeat with thisItem in property list items
				set thisItem_Value to value of thisItem
				set thisIdentifier to identifier of thisItem_Value
				set end of theIdentifieres to thisIdentifier
			end repeat
		end tell
		
		if sortIdentifiers = true then set theIdentifieres to my sort_list(theIdentifieres)
		
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

tell application id "DNtp"
	try
		activate
		set chooseFromListItems to theIdentifieres
		set theChoice to choose from list chooseFromListItems with prompt "Copy Identifier" default items (item 1 of chooseFromListItems) with title "Custom Meta Data"
		if theChoice is false then return
		set the clipboard to (item 1 of theChoice) as string
		
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell

on sort_list(theList)
	considering numeric strings
		set theIndexList to {}
		set theSortedList to {}
		repeat (length of theList) times
			set theLowItem to ""
			repeat with a from 1 to (length of theList)
				if a is not in theIndexList then
					set theCurrentItem to item a of theList as text
					if theLowItem is "" then
						set theLowItem to theCurrentItem
						set theLowItemIndex to a
					else if theCurrentItem comes before theLowItem then
						set theLowItem to theCurrentItem
						set theLowItemIndex to a
					end if
				end if
			end repeat
			set end of theSortedList to theLowItem
			set end of theIndexList to theLowItemIndex
		end repeat
	end considering
	return theSortedList
end sort_list

The following scripts need the scripting addition List & Record Tools. Put it in /Users/Username/Library/ScriptingAdditions/ (create it if necessary).

The second writes meta data identifiers of selected records to a text file on desktop.

Script: Write Custom Meta Data Identifiers to file
-- Write Custom Meta Data Identifiers to file

use scripting additions

property theFilePath : (POSIX path of (path to desktop) & "Metadata Identifiers.txt") as string

tell application id "DNtp"
	try
		set theRecords to selection of viewer window 1 as list
		if theRecords = {} then error "Select some records"
		
		set writeToFile to my write_To_File(("" & linefeed) as string, theFilePath, true)
		
		show progress indicator "Writing Metadata Identifiers... " steps (count theRecords) as string with cancel button
		repeat with thisRecord in theRecords
			step progress indicator (name of thisRecord) as string
			set thisMetadata to custom meta data of thisRecord
			try
				set theRecordPropertyNames to my getPropertyNames(thisMetadata)
				repeat with thisName in theRecordPropertyNames
					set writeToFile to my write_To_File((thisName & linefeed) as string, theFilePath, true)
				end repeat
			end try
		end repeat
		hide progress indicator
		
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on getPropertyNames(theMetadata)
	set theRecordPropertyNames to get user property names theMetadata
end getPropertyNames

on write_To_File(this_data, target_file, append_data)
	try
		set the target_file to the target_file as text
		set the open_target_file to ¬
			open for access POSIX file target_file with write permission
		if append_data is false then ¬
			set eof of the open_target_file to 0
		write this_data as «class utf8» to the open_target_file starting at eof
		close access the open_target_file
		return true
	on error
		try
			close access POSIX file target_file
		end try
		return false
	end try
end write_To_File

Identifiers are not deduplicated as this can be done in a text editor, e.g. BBEdit Text > Process Duplicate Lines.

Finally the main script that deletes given Custom Meta Data from selected records.

There’s a dialog that should prevent accidents, its default button is set to Cancel. Change this or uncomment the whole dialog if you like.

-- Delete Custom Meta Data 

use scripting additions

property deleteMetadataNames : {"mdtest1", "mdtest2"} -- set your Meta Data Identifiers here

tell application id "DNtp"
	try
		set theRecords to selection of viewer window 1 as list
		if theRecords = {} then error "Select some records"
		
		set theButtons to {"Cancel", "Delete"}
		set theButton to button returned of (display alert "Delete this Metadata from selected records?" buttons {item 1, item 2} of theButtons default button 1 message my tid(deleteMetadataNames, linefeed) as critical)
		if theButton = item 1 of theButtons then return
		
		show progress indicator "Deleting given Metadata... " steps (count theRecords) as string with cancel button
		repeat with thisRecord in theRecords
			step progress indicator (name of thisRecord) as string
			set thisMetadata to custom meta data of thisRecord
			try
				set newMetadata to thisMetadata
				set thePropertyNames to my getPropertyNames(thisMetadata)
				repeat with thisPropertyName in thePropertyNames
					if (thisPropertyName as string) is in deleteMetadataNames then set newMetadata to my deleteUserProperty(thisPropertyName as string, newMetadata)
				end repeat
				if newMetadata ≠ thisMetadata then set custom meta data of thisRecord to newMetadata
			end try
		end repeat
		hide progress indicator
		
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell

on tid(theList, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	set theList to theList as text
	set AppleScript's text item delimiters to d
	return theList
end tid

on getPropertyNames(theMetadata)
	set thePropertyNames to get user property names theMetadata
end getPropertyNames

on deleteUserProperty(thePropertyName, theMetadata)
	set theMetadata_new to delete user property thePropertyName in theMetadata
end deleteUserProperty