Deleting all or many records from a datasheet

Hi

What is the quickest way of deleting all records (or maybe a subset based on a view)?

If I display 7224 records and click the select all It will only allow me to delete the records that have come into view, not all 7224.

Is there another way to do this, I do not want to delete the datasheet as it has automations associated to it.

Thanks

Hi @Ben_M , thanks for bringing this up. This is due to pagination behavior, I’ve passed your feedback to the product team for review. They’ll evaluate whether improvements are needed.

For now, records need to be deleted in batches manually. While the API supports bulk deletion, it may not be the best fit if you’re not using custom scripts.

Appreciate your understanding.

Thanks Thea

Can you give me a script that I could use in a scheduled/manual automation?

I have tried many different ways but always get errors; an example of this would be:

// Hardcoded IDs
const spaceId = “XXX”;
const datasheetId = “YYY”;
const viewId = “ZZZ”;

// Fetch space, datasheet, view, and delete records
context.space.getSpace(spaceId).then(space => {
space.getDatasheet(datasheetId).then(datasheet => {
datasheet.getView(viewId).then(view => {
view.getRecords().then(records => {
const deletions = records.map(record => datasheet.deleteRecord(record.recordId));
Promise.all(deletions).then(() => {
return {
deleted: records.length,
message: Deleted ${records.length} records from view '${viewId}' in datasheet '${datasheetId}'
};
});
});
});
});
});

Hi @Ben_M , writing scripts like this isn’t my strongest area either. I’ve tried using GPT to help, but it’s still a bit tricky. @Kelvin will be following up on this issue.

In the meantime, these resources might be helpful:

:blue_book: Bika API Docs – Delete Records: Bika OpenAPI Reference | Bika.ai

:wrench: Developer Guide – OpenAPI Overview: OpenAPI Quick Start | Bika.ai

Appreciate your patience as we continue improving Bika.

Hey @Ben_M ,

Based on your code, you’re trying to filter records through a view and delete them in a loop, right? That makes sense! You could try using the Delete Database Multiple Record API for batch deletion. Since this API is new, it’s not in the SDK yet. Here’s a curl example:

curl --location --request DELETE 'https://bika.ai/api/openapi/bika/v1/spaces/{YOUR_SPACE_ID}/resources/databases/{YOUR_DATABASE_ID}/records?records={RECORD_ID_1}&records={RECORD_ID_2}' \
--header 'Authorization: Bearer {YOUR_BIKA_API_KEY}'

Just pass the record IDs as an array via query parameters. Heads-up: this API handles max 100 records per call, and URL length limits might break if the IDs are super long. Maybe split batches if needed!

Hi Kelvin

I was trying to use an automation with a script in that if i provide the SPACE, DATASHEET and VIEW then delete all records in that view. This is only until I can select all records properly.

Would my method not work?

Your method is ok, just go ahead~ :grinning: :fu:

Hi Kelvin

Can you tell me what is wrong with this code then please, as I cannot get it to work?

// Hardcoded IDs
const spaceId = “XXX”;
const datasheetId = “YYY”;
const viewId = “ZZZ”;

// Fetch space, datasheet, view, and delete records
context.space.getSpace(spaceId).then(space => {
space.getDatasheet(datasheetId).then(datasheet => {
datasheet.getView(viewId).then(view => {
view.getRecords().then(records => {
const deletions = records.map(record => datasheet.deleteRecord(record.recordId));
Promise.all(deletions).then(() => {
return {
deleted: records.length,
message: Deleted ${records.length} records from view '${viewId}' in datasheet '${datasheetId}'
};
});
});
});
});
});

Hi Ben_M,

The code you shared looks like a snippet, right? I can’t really help debug it directly, but I had Claude write a NodeJS script for bulk deleting records that’s actually been tested and works smoothly:

const axios = require('axios');

class BikaRecordsManager {
  constructor(apiKey, spaceId, databaseId) {
    this.apiKey = apiKey;
    this.spaceId = spaceId;
    this.databaseId = databaseId;
    this.baseUrl = 'https://bika.ai/api/openapi/bika/v1';
    this.headers = {
      'Authorization': `Bearer ${apiKey}`
    };
  }

  /**
   * Get all records from specified view
   * @param {string} viewId - View ID
   * @param {number} pageSize - Records per page, default 100
   * @param {number} maxRecords - Maximum records to fetch, default 1000
   * @returns {Promise<Array>} Array of records
   */
  async getAllRecords(viewId, pageSize = 100, maxRecords = 1000) {
    const allRecords = [];
    let pagenum = 1;
    let hasMore = true;

    console.log(`Starting to fetch all records from view ${viewId}...`);

    while (hasMore && allRecords.length < maxRecords) {
      try {
        const url = `${this.baseUrl}/spaces/${this.spaceId}/resources/databases/${this.databaseId}/records`;
        const params = {
          viewId,
          pagenum,
          pageSize,
          maxRecords,
          cellFormat: 'string',
          fieldKey: 'name'
        };

        console.log(`Fetching page ${pagenum}...`);
        
        const response = await axios.get(url, {
          headers: this.headers,
          params
        });

        const records = response.data.data?.records || [];
        
        if (records.length === 0) {
          hasMore = false;
          console.log('No more data available');
        } else {
          allRecords.push(...records);
          console.log(`Fetched ${records.length} records, total: ${allRecords.length}`);
          
          // If returned records less than pageSize, it's the last page
          if (records.length < pageSize) {
            hasMore = false;
          }
          
          pagenum++;
        }
      } catch (error) {
        console.error(`Failed to fetch page ${pagenum}:`, error.response?.data || error.message);
        throw error;
      }
    }

    console.log(`Total fetched ${allRecords.length} records`);
    return allRecords;
  }

  /**
   * Batch delete records
   * @param {Array} recordIds - Array of record IDs to delete
   * @param {number} batchSize - Number of records per batch, default 50
   */
  async batchDeleteRecords(recordIds, batchSize = 50) {
    if (!recordIds || recordIds.length === 0) {
      console.log('No records to delete');
      return;
    }

    console.log(`Starting batch deletion of ${recordIds.length} records...`);
    
    // Delete in batches
    for (let i = 0; i < recordIds.length; i += batchSize) {
      const batch = recordIds.slice(i, i + batchSize);
      
      try {
        const url = `${this.baseUrl}/spaces/${this.spaceId}/resources/databases/${this.databaseId}/records`;
        
        // Build query parameters
        const params = new URLSearchParams();
        batch.forEach(id => params.append('records', id));
        
        const fullUrl = `${url}?${params.toString()}`;
        
        console.log(`Deleting batch ${Math.floor(i / batchSize) + 1}, ${batch.length} records...`);
        
        const response = await axios.delete(fullUrl, {
          headers: this.headers
        });

        console.log(`Successfully deleted ${batch.length} records`);
        
        // Add delay to avoid too frequent requests
        await new Promise(resolve => setTimeout(resolve, 1000));
        
      } catch (error) {
        console.error(`Failed to delete batch ${Math.floor(i / batchSize) + 1}:`, error.response?.data || error.message);
        throw error;
      }
    }
    
    console.log('All records deleted successfully!');
  }

  /**
   * Main function: Delete all records in specified view
   * @param {string} viewId - View ID
   * @param {boolean} confirmDelete - Whether to confirm deletion, default false
   */
  async deleteAllRecordsInView(viewId, confirmDelete = false) {
    try {
      // 1. Get all records
      const records = await this.getAllRecords(viewId);
      
      if (records.length === 0) {
        console.log('No records found in view to delete');
        return;
      }

      // 2. Extract record IDs
      const recordIds = records.map(record => record.recordId).filter(id => id);
      
      console.log(`\n⚠️  WARNING: About to delete ${recordIds.length} records!`);
      console.log(`View ID: ${viewId}`);
      console.log(`Database ID: ${this.databaseId}`);
      console.log(`Space ID: ${this.spaceId}`);
      
      if (!confirmDelete) {
        console.log('\nTo confirm deletion, set confirmDelete = true when calling this function');
        return;
      }

      // 3. Batch delete
      await this.batchDeleteRecords(recordIds);
      
    } catch (error) {
      console.error('Error occurred during deletion process:', error);
      throw error;
    }
  }
}

// Usage example
async function main() {
  // Configuration parameters
  const config = {
    apiKey: 'YOUR_BIKA_API_KEY',        // Replace with your API Key
    spaceId: 'YOUR_SPACE_ID',           // Replace with your Space ID
    databaseId: 'YOUR_DATABASE_ID',     // Replace with your Database ID
    viewId: 'YOUR_VIEW_ID'              // Replace with your View ID
  };

  // Create manager instance
  const manager = new BikaRecordsManager(config.apiKey, config.spaceId, config.databaseId);

  try {
    // Delete all records in specified view
    // Note: Set second parameter to true to actually perform deletion
    await manager.deleteAllRecordsInView(config.viewId, false); // Change to true to confirm deletion
    
    console.log('Operation completed!');
  } catch (error) {
    console.error('Operation failed:', error);
  }
}

// Run script
if (require.main === module) {
  main();
}

module.exports = BikaRecordsManager;

Give this a shot - should handle the deletions properly through the view. Let me know if it works for you!