Replace empty string in field using javascript

I have used the code supplied under "Example: Item Field Changes" on this page: https://www.zotero.org/support/dev/client_coding/javascript_api to successfully change field content. But I receive the message "No items found" if the oldValue is set to empty: "" Is there a way to populate only empty fields using javascript? What I want to do is add "en" to the language field only for those items where the language field is empty.
  • Not sure of the syntax in a search via the JavaScript API, but a search for "does not contain" and "%" should pull up empty fields.
  • Thank you for your comment, but how could I do a replace or add to an empty field for more than 5000 items using the program's search functionality?
  • I would have to refer you back to the the page that you linked above. Basically you would set up a search as documented at the bottom of the page, satisfy yourself that it's fetching the right items, then add the code to perform the edit and save.

    Editing 5000 items via the JS API is no problem: you just need to be very careful to check that the code will do exactly what you want before running it for serious.
  • Thank you, my challenge is to set up a search that replaces an empty language field with "en", but the code does not work if the search field is empty, it does work as expected if it contains data. Any suggestions how to achieve that would be highly appreciated.
  • Right, what fbennett is suggesting is to try
    oldValue = "%";
    ...
    s.addCondition(fieldName, 'contains', oldValue);

    does that not work?
  • edited August 24, 2019
    Sorry, I was away on errands (it was midday here in Asia). I tried a search following the page instructions. I had to peek into the Zotero source to find it, but the search predicate that turned up empties was doesNotContain. This should work:

    s.addCondition(fieldname, 'doesNotContain', '%');

    It might be good to add the most common search predicates to the instructions.

    (A search for '%' with contains will find all entries that already have content, which are definitely not the desired targets.)
  • edited August 24, 2019
    You can just leave the field empty. There's no need to put in a '%'.

    (It's a leaky abstraction from SQLite that the percent character even has meaning, and that will likely be fixed in the future in favor of more standard wildcards. In the meantime, the search term is already wrapped with '%' on both sides, so '%' just becomes '%%%', which is the same as '%%'.)
  • edited August 24, 2019
    Thank you all. Using your example code I now get an error: "Error '87' is not a valid field for type 1". I copied the code clean from the webpage, added
    var fieldName = "language";
    var oldValue = "%";
    var newValue = "en";

    and
    s.addCondition(fieldname, 'doesNotContain', '');
    It does not matter whether I enter oldValue, '%' or '' at the end of the line above. I receive the same error. I am no programmer and feeling adventurous.
  • That means you're trying to add a field to a note. Try adding these conditions:

    s.addCondition('itemType', 'isNot', 'note');
    s.addCondition('itemType', 'isNot', 'attachment');
  • It might be what the error code says, but I am not trying to add to a note. I want to add "en" to the language field where the language field is empty.
    It is these two lines that are causing me trouble:
    var oldValue = "%";
    s.addCondition(fieldName, 'doesNotContain', oldValue);

  • I'm saying it's giving you an error because the code you're using is trying to assign a field to a note, which isn't allowed. And I'm giving you the code to fix that by excluding notes and attachments from the search.
  • Sorry for misunderstanding you, now I get this return value: Error: '87' is not a valid field for type 32
    My code is as follows:
    var fieldName = "language";
    var oldValue = "%";
    var newValue = "en";

    var fieldID = Zotero.ItemFields.getID(fieldName);
    var s = new Zotero.Search();
    s.libraryID = Zotero.Libraries.userLibraryID;
    s.addCondition('itemType', 'isNot', 'note');
    s.addCondition('itemType', 'isNot', 'attachment');
    s.addCondition(fieldName, 'doesNotContain', '');
    var ids = await s.search();
    if (!ids.length) {
    return "No items found";
  • The correct way to fix this would be to use Zotero.ItemFields.isValidForType(fieldID, itemTypeID), but you could just add a try/catch around the save.
  • Thank you, but as I am no programmer, I don't know where to put that code in the example code or how to add a try/catch around the save. Would it be possible to present the code?
  • @haraldaa:

    It turns out that the "language" field shown in the Computer Program type is actually the "programmingLanguage." That type doesn't have an ordinary language field, which is why edits to that type are failing for you. If you add this line to the conditions, it should help:

    s.addCondition('itemType', 'isNot', 'computerProgram');
  • Thank you all for your help. Now I managed to add "en" to the language field for records with an empty language field. For those interested in the code. This is the code that worked:
    var fieldName = "language";
    var oldValue = "%";
    var newValue = "en";

    var fieldID = Zotero.ItemFields.getID(fieldName);
    var s = new Zotero.Search();
    s.libraryID = Zotero.Libraries.userLibraryID;
    s.addCondition('itemType', 'isNot', 'note');
    s.addCondition('itemType', 'isNot', 'attachment');
    s.addCondition('itemType', 'isNot', 'computerProgram');
    s.addCondition(fieldName, 'doesNotContain', oldValue);
    var ids = await s.search();
    if (!ids.length) {
    return "No items found";
    }
    await Zotero.DB.executeTransaction(async function () {
    for (let id of ids) {
    let item = await Zotero.Items.getAsync(id);
    let mappedFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(item.itemTypeID, fieldName);
    item.setField(mappedFieldID ? mappedFieldID : fieldID, newValue);
    await item.save();
    }
    });
    return ids.length + " item(s) updated";

    Remember to back up your database before trying and turn off automatic syncing!
Sign In or Register to comment.