跳到主要内容

Index files in a folder by adding a document number prefix

This example demonstrates how to assign simple document numbers to files in a specific DocSpace folder. The script loads the folder contents, generates an index prefix in the format TYPE-YEAR-COUNTER, and renames each file by adding this prefix to the beginning of the file title.

Before you start

  1. Replace https://yourportal.onlyoffice.com and YOUR_API_KEY with your actual DocSpace portal URL and API key. Ensure you have the necessary data and permissions to perform these operations.
  2. Before you can make requests to the API, you need to authenticate. Check out the Personal access tokens page to learn how to obtain and use access tokens.
Full example
// Set API base URL
const API_HOST = process.env.DOCSPACE_API_HOST; // Set DOCSPACE_API_HOST in env (recommended). For quick tests you can temporarily paste your portal URL here.
const API_KEY = process.env.DOCSPACE_API_KEY; // Set DOCSPACE_API_KEY in env (recommended). For quick tests you can temporarily paste token here.

// Folder to index
const TARGET_FOLDER_ID = 'folder_id_here';

// Index type prefix
const INDEX_TYPE = 'DOC';

// Counter width, for example: 4 -> 0001
const COUNTER_WIDTH = 4;

// Headers with API key for authentication
const HEADERS = {
Accept: 'application/json',
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
};

async function docspaceRequest(path: string, method: string = 'GET', body: any = null) {
const url = `${API_HOST}${path}`;

try {
const res = await fetch(url, {
method,
headers: HEADERS,
body: body ? JSON.stringify(body) : undefined,
});

if (!res.ok) {
const t = await res.text();
console.log(`Request failed. Status: ${res.status}, Message: ${t}`);
return null;
}

return res.json();
} catch (err: any) {
console.log(`Request error: ${err?.message || err}`);
return null;
}
}

// Step 1: Get folder contents
async function getFolderContents(folderId: string) {
const data = await docspaceRequest(`/api/2.0/files/folder/${folderId}`, 'GET');
if (!data || typeof data !== 'object') return [];

const resp = (data as any).response != null ? (data as any).response : data;

if (Array.isArray(resp)) return resp;

if (resp && typeof resp === 'object') {
const files = (resp as any).files;
return Array.isArray(files) ? files : [];
}

return [];
}

// Helper: detect if item is a file
function isFileItem(item: any) {
if (!item || typeof item !== 'object') return false;

const isFolderFlag = item.isFolder === true || item.folder === true;
if (isFolderFlag) return false;

const fileType = String(item.fileType || item.type || '').toLowerCase();
if (fileType && fileType !== 'folder') return true;

return Boolean(item.id && item.title && !isFolderFlag);
}

// Step 2: Build index prefix TYPE-YEAR-COUNTER
function buildIndexPrefix(docType: string, counter: number) {
const year = new Date().getFullYear();
const padded = String(counter).padStart(COUNTER_WIDTH, '0');
return `${docType}-${year}-${padded}`;
}

// Step 3: Build new title
function buildIndexedTitle(prefix: string, originalTitle: string) {
return `${prefix}_${originalTitle}`;
}

// Step 4: Rename file
async function renameFile(fileId: string, newTitle: string) {
const payload = { title: newTitle };

const data = await docspaceRequest(`/api/2.0/files/file/${fileId}`, 'PUT', payload);
return Boolean(data);
}

// Run sequence
(async () => {
try {
const items = await getFolderContents(String(TARGET_FOLDER_ID));
const files = items.filter(isFileItem);

if (!files.length) {
console.log('No files found in the folder.');
return;
}

let counter = 1;

for (const item of files) {
const fileId = String(item.id);
const originalTitle = String(item.title || 'file');

const prefix = buildIndexPrefix(INDEX_TYPE, counter);
const newTitle = buildIndexedTitle(prefix, originalTitle);

const ok = await renameFile(fileId, newTitle);
if (ok) {
console.log(`Renamed: "${originalTitle}" -> "${newTitle}"`);
}

counter += 1;
}

console.log('Indexing complete.');
} catch (err: any) {
console.error(err?.message || err);
}
})();

Step 1: Retrieve folder contents

A GET request is sent to /api/2.0/files/folder/:folderId to retrieve the folder contents.

The response typically includes:

  • files: files stored directly in this folder
  • folders: subfolders (this example does not scan subfolders)
async function getFolderContents(folderId: string) {
const data = await docspaceRequest(`/api/2.0/files/folder/${folderId}`, 'GET');
if (!data || typeof data !== 'object') return [];

const resp = (data as any).response != null ? (data as any).response : data;

if (Array.isArray(resp)) return resp;

if (resp && typeof resp === 'object') {
const files = (resp as any).files;
return Array.isArray(files) ? files : [];
}

return [];
}

Step 2: Select only files

The script filters the returned items and keeps only file entries (folders are skipped). This ensures that only documents are renamed.

function isFileItem(item: any) {
if (!item || typeof item !== 'object') return false;

const isFolderFlag = item.isFolder === true || item.folder === true;
if (isFolderFlag) return false;

const fileType = String(item.fileType || item.type || '').toLowerCase();
if (fileType && fileType !== 'folder') return true;

return Boolean(item.id && item.title && !isFolderFlag);
}

Step 3: Generate an index prefix

For each file, the script generates a prefix:

  • INDEX_TYPE: a short document type label (for example, DOC)
  • YEAR: current year
  • COUNTER: sequential number padded with COUNTER_WIDTH

Example:

  • DOC-2025-0001
  • DOC-2025-0002
function buildIndexPrefix(docType: string, counter: number) {
const year = new Date().getFullYear();
const padded = String(counter).padStart(COUNTER_WIDTH, '0');
return `${docType}-${year}-${padded}`;
}

Step 4: Rename the file by adding the prefix

A PUT request is sent to /api/2.0/files/file/:fileId with:

  • title: the new file title (prefix + original title)

This updates the file name in the folder while keeping the file ID the same. In this example, notify_admin()/notifyAdmin() is a placeholder that prints the message. In a real integration, replace it with your email, webhook, or incident system.

async function renameFile(fileId: string, newTitle: string) {
const payload = { title: newTitle };

const data = await docspaceRequest(`/api/2.0/files/file/${fileId}`, 'PUT', payload);
return Boolean(data);
}