Managing Monday.com Items and Subitems Updating Existing Monday.com Subitems

When syncing complex data with Monday.com, updating subitems one by one inside a loop can quickly drain your task limits and slow down your workflows. This guide explains how to use a custom code step in Zapier to update multiple subitems simultaneously using a single, batched GraphQL mutation.

By passing comma-separated lists of data into a single JavaScript step, you can bypass the need for looping through individual "Update Item" actions.

Why use batched mutations?
A batched mutation combines multiple update commands into a single API request. This dramatically improves performance, reduces API rate limiting, and saves Zapier tasks.

How the batch update works

The script takes your comma-separated lists of subitem IDs and product details, maps them together, dynamically fetches the correct subitem board, and sends one comprehensive update to Monday.com.

flowchart TD
    A["Receive Zapier Inputs (Comma-separated)"] --> B["Build Product Lookup Map"]
    B --> C["Fetch Subitem Board ID from Monday.com"]
    C --> D["Construct Batched GraphQL Mutation"]
    D --> E["Execute Single API Call"]
    E --> F["Generate Diagnostic Output"]

Configuration Guide

To implement this in your workflow, you will need to configure a Code by Zapier (Run JavaScript) step.

  1. 1

    Configure Input Data

    In your Zapier Code step, map the following keys in the Input Data section. Ensure the values coming from previous steps are comma-separated strings.

    Input KeyDescription
    mondayApiTokenYour Monday.com API v2 Token.
    teamMemberThe default team member to assign (if not locked).
    itemsToUpdateComma-separated list of Monday subitem IDs.
    productsToUpdateComma-separated list of Product IDs.
    productsPriceUpdateComma-separated list of prices.
    dbProductIdsDatabase product IDs (used as the lookup key).
    dbQboIdsQuickBooks Online IDs.
    dbQBCategoryQuickBooks Categories.
    dbSpecialActionSpecial action labels.
    dbTitleCodesTitle codes for the line items.
    dbTitleOrdersTitle order numbers.
    dbTimeCalcsDuration/time calculations.
    dbTimeCalcCodesTime calculation codes.
    dbLockTeamMembersLock status for team member assignment.
  2. 2

    Add the JavaScript Code

    Copy and paste the batched mutation script into the Code field.

    Check your Column IDs
    The code below uses specific Monday.com column IDs (e.g., text_Mjj2AaAS, status_mkkaxp21). You must update these column IDs to match the actual column IDs on your Monday.com subitem board.

    const MONDAY_API_TOKEN = inputData.mondayApiToken;
    const teamMember = inputData.teamMember || "";
    
    // Helper: split comma-separated string
    const split = function(str) {
      return str ? str.split(",").map(function(x) { return x.trim(); }).filter(Boolean) : [];
    };
    
    // Parse items to update
    const itemsToUpdate       = split(inputData.itemsToUpdate);
    const productsToUpdate    = split(inputData.productsToUpdate);
    const productsPriceUpdate = split(inputData.productsPriceUpdate);
    
    if (itemsToUpdate.length === 0) {
      output = { Status: "NothingToUpdate", TotalProcessed: 0 };
      return;
    }
    
    // Build Items Database lookup map
    const dbProductIds      = split(inputData.dbProductIds);
    const dbQboIds          = split(inputData.dbQboIds);
    const dbQBCategory      = split(inputData.dbQBCategory);
    const dbSpecialAction   = split(inputData.dbSpecialAction);
    const dbTitleCodes      = split(inputData.dbTitleCodes);
    const dbTitleOrders     = split(inputData.dbTitleOrders);
    const dbTimeCalcs       = split(inputData.dbTimeCalcs);
    const dbDefaultMembers  = split(inputData.dbDefaultMembers);
    const dbLockTeamMembers = split(inputData.dbLockTeamMembers);
    const dbTimeCalcCodes   = split(inputData.dbTimeCalcCodes);
    
    const itemsDB = {};
    dbProductIds.forEach(function(id, i) {
      itemsDB[id] = {
        qboId:          dbQboIds[i]          || "",
        qbCategory:     dbQBCategory[i]      || "",
        specialAction:  dbSpecialAction[i]   || "",
        titleCode:      dbTitleCodes[i]      || "",
        titleOrder:     dbTitleOrders[i]     || "",
        timeCalc:       dbTimeCalcs[i]       || "",
        timeCalcCode:   dbTimeCalcCodes[i]   || "",
        defaultMember:  dbDefaultMembers[i]  || "",
        lockTeamMember: dbLockTeamMembers[i] || ""
      };
    });
    
    // Resolve subitem board ID from the first subitem
    const boardQuery = "{ items(ids: [" + itemsToUpdate[0] + "]) { board { id } } }";
    const boardRes = await fetch("https://api.monday.com/v2", {
      method: "POST",
      headers: {
        "Content-Type":  "application/json",
        "Authorization": MONDAY_API_TOKEN,
        "API-Version":   "2024-01"
      },
      body: JSON.stringify({ query: boardQuery })
    });
    const boardData = await boardRes.json();
    const boardItems = boardData.data && boardData.data.items ? boardData.data.items : [];
    const SUBITEM_BOARD_ID = boardItems[0] && boardItems[0].board ? boardItems[0].board.id : null;
    
    if (!SUBITEM_BOARD_ID) throw new Error("Could not resolve subitem board ID from item: " + itemsToUpdate[0]);
    
    // Build batched mutation
    const mutationParts = [];
    const results       = [];
    
    for (let i = 0; i < itemsToUpdate.length; i++) {
      const subitemId = itemsToUpdate[i];
      const productId = productsToUpdate[i];
      const price     = productsPriceUpdate[i] || "";
      const dbItem    = itemsDB[productId] || {};
      const foundInDB = Object.prototype.hasOwnProperty.call(itemsDB, productId);
    
      // Business Logic: Suppress title columns if order > 900
      const rawTitleOrder      = parseFloat(dbItem.titleOrder) || 0;
      const titleCode          = rawTitleOrder > 900 ? "" : (dbItem.titleCode    || "");
      const titleOrder         = rawTitleOrder > 900 ? "" : (dbItem.titleOrder   || "");
      const timeCalcCode       = rawTitleOrder > 900 ? "" : (dbItem.timeCalcCode || "");
      const titleParsingOutput = titleCode && titleOrder ? titleCode + "-" + titleOrder : "";
    
      // Build column values (Update column IDs here to match your board)
      const cols = {};
      if (productId)             cols["text_Mjj2AaAS"]    = productId;
      if (price)                 cols["text_Mjj2CDRz"]    = price;
      if (dbItem.qboId)          cols["text_mkkq88hk"]    = dbItem.qboId;
      if (dbItem.qbCategory)     cols["status_mkkaxp21"]  = { label: dbItem.qbCategory };
      if (dbItem.specialAction)  cols["color_mkx2z43z"]   = { label: dbItem.specialAction };
      if (titleOrder)            cols["numbers_mkkw8n33"] = parseFloat(titleOrder) || 0;
      if (titleOrder)            cols["text_Mjj2A3O6"]    = titleOrder;
      if (titleCode)             cols["text_Mjj2G5AI"]    = titleCode;
      if (timeCalcCode)          cols["text_mkx8k859"]    = timeCalcCode;
      if (dbItem.lockTeamMember) cols["color_mkwdgmb0"]   = { label: dbItem.lockTeamMember };
      if (titleParsingOutput)    cols["text_Mjj2o8qB"]    = titleParsingOutput;
      if (dbItem.timeCalc)       cols["color_mkx8mezg"]   = { label: dbItem.timeCalc };
      
      // Assign team member unless locked
      if (dbItem.lockTeamMember !== "Locked" && teamMember) {
          cols["color_mkszrf28"] = { label: teamMember };
      }
    
      const colStr = JSON.stringify(JSON.stringify(cols));
      const alias  = "item_" + i;
    
      // Add to batch
      mutationParts.push(
        alias + ": change_multiple_column_values(board_id: " + SUBITEM_BOARD_ID + ", item_id: " + subitemId + ", column_values: " + colStr + ") { id }"
      );
    
      // Store diagnostics
      results.push({
        subitemId: subitemId,
        productId: productId,
        foundInDB: foundInDB,
        rawTitleOrder: rawTitleOrder,
        titleSuppressed: rawTitleOrder > 900,
        qboId: dbItem.qboId || "(MISSING)",
        qbCategory: dbItem.qbCategory || "(MISSING)",
        specialAction: dbItem.specialAction || "(MISSING)"
      });
    }
    
    // Execute single batched API call
    const batchMutation = "mutation { " + mutationParts.join("\n") + " }";
    
    const response = await fetch("https://api.monday.com/v2", {
      method: "POST",
      headers: {
        "Content-Type":  "application/json",
        "Authorization": MONDAY_API_TOKEN,
        "API-Version":   "2024-01"
      },
      body: JSON.stringify({ query: batchMutation })
    });
    
    const data = await response.json();
    if (data.errors) throw new Error("Monday API error: " + JSON.stringify(data.errors));
    
    // Diagnostic Output Generation
    const missingFromDB = results.filter(function(r) { return !r.foundInDB; });
    const missingQbo = results.filter(function(r) { return r.qboId === "(MISSING)"; });
    
    output = {
      TotalProcessed: results.length,
      Status: "Completed",
      MissingFromDB_Count: missingFromDB.length,
      MissingFromDB_Ids: missingFromDB.map(function(r) { return r.productId; }).join(", ") || "(none)",
      MissingQbo_Count: missingQbo.length,
      MissingQbo_Ids: missingQbo.map(function(r) { return r.productId; }).join(", ") || "(none)"
    };
  3. 3

    Review Diagnostic Outputs

    The script outputs a diagnostic summary instead of raw API responses. You can use these output fields in subsequent Zapier steps (like sending a Slack alert if MissingFromDB_Count is greater than 0) to ensure data integrity.

Built-in Business Rules

The script includes specific business logic to handle edge cases automatically during the update process.

Title Suppression Logic

If a subitem's titleOrder evaluates to greater than 900, the script automatically suppresses (clears) the titleCode, titleOrder, and timeCalcCode fields for that specific subitem. This prevents internal or non-standard items from cluttering your standard title sequences.

Team Member Assignment

The script will assign the default teamMember passed in the input data to the subitem, unless the lockTeamMember database field is set to exactly "Locked". If it is locked, the assignment is skipped to preserve the existing owner.