View

The View object represents a view of a table in your NocoDB base. A view shows your table data with filters, sorts, and other customizations.

Overview

Use views in NocoDB to:

  • Apply filters to show only specific records from a table
  • Define custom sorting for records
  • Show or hide specific fields

In NocoDB Scripts, use View objects to work with these filtered subsets of data. You do not have to write the filtering logic in your script.

Properties

PropertyTypeDescription
idstringThe unique identifier of the view
namestringThe name of the view
descriptionstring | nullThe description of the view (if any)
typestringThe type of view (for example, 'grid', 'form', 'gallery', 'kanban', 'calendar')
tableTableReference to the parent table that this view belongs to

Methods

selectRecordsAsync

Queries records from the view. Optional parameters set the fields, the sorting, and the pagination.

Parameters:

  • options (optional): Object with the following properties:
    • fields (Array<Field | string>): Specific fields to include in the result. If you do not specify fields, the result includes all fields.
    • sorts (Array<{field: Field | string, direction: 'asc' | 'desc'}>): Sorting options
    • recordIds (Array<string>): Specific record IDs to retrieve
    • pageSize (number): Maximum number of records to return per page (default: 50)
    • page (number): Page number for pagination (default: 1)
    • where (string): A where filter condition. It adds to the existing view filters

Returns: Promise<RecordQueryResult>: A promise that resolves to a RecordQueryResult object with pagination support

Example:

// Get the Projects table and Active Projects view
const projectsTable = base.getTable('Projects');
const activeProjectsView = projectsTable.getView('Active Projects');

// Query records from the view
const queryResult = await activeProjectsView.selectRecordsAsync({
  fields: ['Project Name', 'Status', 'Deadline', 'Assigned To'],
  sorts: [
    { field: 'Deadline', direction: 'asc' }
  ],
  pageSize: 50
});

while(queryResult.hasMoreRecords) {
  await queryResult.loadMoreRecords()
}

output.text(`Found ${queryResult.records.length} active projects.`);

// Process the records
for (const record of queryResult.records) {
  const projectName = record.getCellValue('Project Name');
  const deadline = record.getCellValue('Deadline');
  const assignedTo = record.getCellValue('Assigned To');
  
  const assigneeName = assignedTo ? assignedTo.name : 'Unassigned';
  
  output.text(`- ${projectName} due on ${deadline} - Assigned to: ${assigneeName}`);
}

selectRecordAsync

Gets one record from the view by its ID. The view's filters and permissions apply.

Parameters:

  • recordId (string): The ID of the record to retrieve
  • options (optional): Object with the following properties:
    • fields (Array<Field | string>): Specific fields to include in the result. The result always includes the primary key and primary value fields.

Returns: Promise<NocoDBRecord | null>: A promise that resolves to the NocoDBRecord object. It resolves to null if the record is not found, if the view filters it out, or if an AxiosError occurs

Example:

// Get a specific record through a view
const tasksTable = base.getTable('Tasks');
const myTasksView = tasksTable.getView('My Tasks');

const recordId = '123';
const task = await myTasksView.selectRecordAsync(recordId, {
  fields: ['Task Name', 'Status', 'Due Date', 'Notes']
});

if (task) {
  output.text(`Task: ${task.getCellValue('Task Name')}`);
  output.text(`Status: ${task.getCellValue('Status')}`);
  output.text(`Due Date: ${task.getCellValue('Due Date')}`);
  output.text(`Notes: ${task.getCellValue('Notes')}`);
} else {
  output.text(`Record with ID ${recordId} not found in this view.`);
  // Note: The record might exist in the table but be filtered out by the view
}

Using Views for Filtering

A primary benefit of views is filtering. Use a view to filter data, and do not write complex filtering logic in your scripts.

// Example: Processing overdue tasks
const tasksTable = base.getTable('Tasks');
const overdueTasksView = tasksTable.getView('Overdue Tasks');

// This view already has filters for tasks where Due Date < Today and Status != Completed
const overdueTasks = await overdueTasksView.selectRecordsAsync({
  fields: ['Task Name', 'Due Date', 'Assigned To', 'Status']
});

while(overdueTasks.hasMoreRecords) {
  await overdueTasks.loadMoreRecords()
}

// Create a notification summary
output.markdown('# Overdue Tasks Summary');
output.text(`There are ${overdueTasks.records.length} overdue tasks.`);

// Group tasks by assignee
const tasksByAssignee = {} as Record<string, {
  name: string,
  tasks: Array<{name: string, dueDate: string}>
}>;
for (const task of overdueTasks.records) {
  const assignee = task.getCellValue('Assigned To');
  const assigneeId = assignee ? assignee.id : 'unassigned';
  const assigneeName = assignee ? assignee.name : 'Unassigned';
  
  if (!tasksByAssignee[assigneeId]) {
    tasksByAssignee[assigneeId] = {
      name: assigneeName,
      tasks: []
    };
  }
  
  tasksByAssignee[assigneeId].tasks.push({
    name: task.getCellValue('Task Name'),
    dueDate: task.getCellValue('Due Date')
  });
}

// Output summary by assignee
for (const [assigneeId, assigneeData] of Object.entries(tasksByAssignee)) {
  output.markdown(`## ${assigneeData.name}`);
  for (const task of assigneeData.tasks) {
    const daysOverdue = Math.floor((new Date() - new Date(task.dueDate)) / (1000 * 60 * 60 * 24));
    output.text(`- ${task.name} (${daysOverdue} days overdue)`);
  }
}

Creating Interactive Reports Using Views

Use views to create interactive reports for different data segments.

// Let the user choose a view from the Sales table
const salesTable = base.getTable('Sales');
const viewOptions = salesTable.views.map(view => view.name);

const selectedViewName = await input.selectAsync(
  'Select a sales report view to analyze:',
  viewOptions
);

const selectedView = salesTable.getView(selectedViewName);
const sales = await selectedView.selectRecordsAsync({
  fields: ['Date', 'Amount', 'Product', 'Sales Rep', 'Region']
});

while(sales.hasMoreRecords) {
  await sales.loadMoreRecords()
}

// Calculate summary statistics
let totalSales = 0;
const salesByRep = {};
const salesByProduct = {};
const salesByRegion = {};

for (const record of sales.records) {
  const amount = record.getCellValue('Amount') || 0;
  const rep = record.getCellValue('Sales Rep');
  const product = record.getCellValue('Product');
  const region = record.getCellValue('Region');
  
  totalSales += amount;
  
  // Sales by rep
  if (rep) {
    const repName = rep.name;
    if (!salesByRep[repName]) {
      salesByRep[repName] = 0;
    }
    salesByRep[repName] += amount;
  }
  
  // Sales by product
  if (product) {
    if (!salesByProduct[product]) {
      salesByProduct[product] = 0;
    }
    salesByProduct[product] += amount;
  }
  
  // Sales by region
  if (region) {
    if (!salesByRegion[region]) {
      salesByRegion[region] = 0;
    }
    salesByRegion[region] += amount;
  }
}

// Output the report
output.markdown(`# Sales Report: ${selectedViewName}`);
output.text(`Total Sales: $${totalSales.toFixed(2)}`);
output.text(`Number of Transactions: ${sales.records.length}`);
output.text(`Average Transaction: $${(totalSales / sales.records.length).toFixed(2)}`);

// Display sales by rep
output.markdown('## Sales by Representative');
const salesByRepData = Object.entries(salesByRep)
  .map(([rep, amount]) => ({ Rep: rep, Amount: amount }))
  .sort((a, b) => b.Amount - a.Amount);
output.table(salesByRepData);

// Display sales by product
output.markdown('## Sales by Product');
const salesByProductData = Object.entries(salesByProduct)
  .map(([product, amount]) => ({ Product: product, Amount: amount }))
  .sort((a, b) => b.Amount - a.Amount);
output.table(salesByProductData);

// Display sales by region
output.markdown('## Sales by Region');
const salesByRegionData = Object.entries(salesByRegion)
  .map(([region, amount]) => ({ Region: region, Amount: amount }))
  .sort((a, b) => b.Amount - a.Amount);
output.table(salesByRegionData);

Best Practices

  1. Use views for filtering: Use views to apply complex filters. Do not write filtering logic in your script.

  2. Remember views are read-only: View objects can only query records. You create and update records at the table level.

  3. Combine with Table operations: Use views to read and filter data. Use table methods to write data.

  4. Await async operations: Always use await when you call async methods. This makes sure that the code runs in the correct order.

Last updated on

Latest product updates?See Changelog
Stay in the loop? Follow us onLinkedInLinkedInYouTubeYouTubeXX