Перейти к основному содержимому

Файлы (Files)

Поле типа Файлы позволяет загружать и хранить несколько файлов любого типа.

Основные характеристики

  • Количество файлов: Множественные файлы
  • Максимальное количество: Настраивается (по умолчанию без ограничений)
  • Максимальный размер: Настраивается для каждого файла
  • Типы файлов: Любые (с возможностью ограничения)
  • Хранение: В интегрированном хранилище EMD Cloud
  • Порядок: Поддержка сортировки файлов

Настройки поля

При создании поля типа "Файлы" доступны следующие настройки:

  • Название поля: Отображаемое имя поля
  • Системное имя: Уникальный идентификатор для API
  • Описание: Подсказка для пользователей
  • Обязательное поле: Требовать загрузки хотя бы одного файла
  • Минимальное количество: Минимальное количество файлов
  • Максимальное количество: Максимальное количество файлов
  • Максимальный размер: Ограничение размера каждого файла (в МБ)
  • Допустимые типы: Ограничение по типам файлов (MIME types)
  • Автоматическое превью: Генерировать превью для изображений

Примеры использования

Галерея товара

{
"name": "images",
"type": "files",
"required": true,
"minFiles": 1,
"maxFiles": 10,
"maxSize": 5,
"allowedTypes": ["image/jpeg", "image/png", "image/webp"]
}

Документы проекта

{
"name": "documents",
"type": "files",
"maxFiles": 20,
"allowedTypes": [
"application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
]
}

Вложения к задаче

{
"name": "attachments",
"type": "files",
"maxSize": 10
}

Работа через API

Загрузка нескольких файлов

// Загрузка файлов по одному
const uploadedFiles = [];
for (const file of fileInput.files) {
const formData = new FormData();
formData.append('file', file);
const uploaded = await emd.storage.upload(formData);
uploadedFiles.push(uploaded.id);
}

// Создание записи с файлами
const record = await emd.database.collection('products').create({
name: 'Ноутбук Dell XPS 15',
images: uploadedFiles
});

Загрузка с созданием записи

const formData = new FormData();
formData.append('name', 'Ноутбук Dell XPS 15');

// Добавление нескольких файлов
for (const file of fileInput.files) {
formData.append('images', file);
}

const record = await emd.database.collection('products').create(formData);

Получение списка файлов

const record = await emd.database.collection('products').get(recordId);

console.log(record.images);
// [
// {
// id: "file_123",
// name: "front.jpg",
// size: 245678,
// mimeType: "image/jpeg",
// url: "https://cdn.emd.one/files/file_123.jpg",
// order: 0
// },
// {
// id: "file_124",
// name: "back.jpg",
// size: 198765,
// mimeType: "image/jpeg",
// url: "https://cdn.emd.one/files/file_124.jpg",
// order: 1
// }
// ]

Добавление файлов к существующей записи

// Получить текущие файлы
const record = await emd.database.collection('products').get(recordId);

// Загрузить новый файл
const formData = new FormData();
formData.append('file', newFile);
const uploaded = await emd.storage.upload(formData);

// Добавить к существующим
await emd.database.collection('products').update(recordId, {
images: [...record.images.map(f => f.id), uploaded.id]
});

Удаление файла из списка

const record = await emd.database.collection('products').get(recordId);

// Удалить файл с определенным ID
const fileIdToRemove = 'file_123';
const updatedFiles = record.images
.filter(f => f.id !== fileIdToRemove)
.map(f => f.id);

await emd.database.collection('products').update(recordId, {
images: updatedFiles
});

// Опционально: удалить файл из хранилища
await emd.storage.delete(fileIdToRemove);

Изменение порядка файлов

const record = await emd.database.collection('products').get(recordId);

// Переставить файлы местами
const reorderedFiles = [
record.images[2].id,
record.images[0].id,
record.images[1].id
];

await emd.database.collection('products').update(recordId, {
images: reorderedFiles
});

Работа с галереями изображений

Получение превью

const record = await emd.database.collection('products').get(recordId);

// Первое изображение (главное)
const mainImage = record.images[0];
const mainImageUrl = mainImage.url;
const mainImageThumb = mainImage.thumbnails.medium;

// Все превью для галереи
const gallery = record.images.map(img => ({
original: img.url,
thumbnail: img.thumbnails.small,
title: img.name
}));

Отображение галереи в HTML

const record = await emd.database.collection('products').get(recordId);

const galleryHTML = record.images.map(img => `
<div class="gallery-item">
<img src="${img.thumbnails.medium}" alt="${img.name}" />
</div>
`).join('');

document.getElementById('gallery').innerHTML = galleryHTML;

Массовые операции

Загрузка множества файлов с прогрессом

const files = Array.from(fileInput.files);
const uploadedFiles = [];

for (let i = 0; i < files.length; i++) {
const formData = new FormData();
formData.append('file', files[i]);

const uploaded = await emd.storage.upload(formData, {
onProgress: (progress) => {
console.log(`Файл ${i + 1}/${files.length}: ${progress}%`);
}
});

uploadedFiles.push(uploaded.id);
}

await emd.database.collection('products').update(recordId, {
images: uploadedFiles
});

Удаление всех файлов

const record = await emd.database.collection('products').get(recordId);

// Удалить все файлы из хранилища
for (const file of record.images) {
await emd.storage.delete(file.id);
}

// Очистить поле
await emd.database.collection('products').update(recordId, {
images: []
});

Поиск по файлам

Найти записи с файлами

// Записи, у которых есть хотя бы один файл
const records = await emd.database.collection('products').find({
images: { $exists: true, $ne: [] }
});

// Записи с определенным количеством файлов
const records = await emd.database.collection('products').find({
'images.$size': 5
});

Валидация

Ограничение количества файлов

{
"name": "images",
"type": "files",
"minFiles": 3,
"maxFiles": 10
}

Проверка при создании

try {
const record = await emd.database.collection('products').create({
name: 'Товар',
images: uploadedFiles
});
} catch (error) {
if (error.code === 'MIN_FILES_REQUIRED') {
console.error('Загрузите минимум 3 изображения');
}
if (error.code === 'MAX_FILES_EXCEEDED') {
console.error('Максимум 10 изображений');
}
}

Оптимизация производительности

Ленивая загрузка превью

const record = await emd.database.collection('products').get(recordId, {
fields: ['name', 'images.id', 'images.thumbnails.small']
});

Пагинация файлов

Для записей с большим количеством файлов:

const record = await emd.database.collection('documents').get(recordId);
const filesPerPage = 20;
const page = 1;

const paginatedFiles = record.attachments.slice(
(page - 1) * filesPerPage,
page * filesPerPage
);

Метаданные файлов

Каждый файл в массиве содержит:

{
id: "file_123",
name: "image.jpg",
originalName: "Фото товара.jpg",
size: 1245678,
mimeType: "image/jpeg",
url: "https://cdn.emd.one/files/file_123.jpg",
thumbnails: {
small: "...",
medium: "...",
large: "..."
},
order: 0,
uploadedAt: "2025-11-25T10:30:00Z",
uploadedBy: "user_456"
}

Рекомендации

  • Устанавливайте разумные ограничения на количество файлов
  • Используйте превью для изображений в списках
  • Реализуйте ленивую загрузку для больших галерей
  • Показывайте прогресс загрузки для множественных файлов
  • Позволяйте пользователям менять порядок файлов
  • Добавляйте возможность удаления отдельных файлов
  • Оптимизируйте изображения перед загрузкой
  • Используйте CDN для быстрой доставки файлов

Типичные сценарии

Галерея товара

  • Минимум 1 изображение
  • Максимум 10 изображений
  • Первое изображение — главное
  • Возможность изменения порядка

Документы проекта

  • Без ограничения количества
  • Разные типы файлов (PDF, DOC, XLS)
  • Сортировка по дате загрузки

Вложения к задаче

  • Без ограничения количества
  • Любые типы файлов
  • Возможность добавления/удаления

Отличие от других типов

  • Files vs File: Files для множественных файлов, File для одного
  • Files vs JSON: Files для файлов, JSON для структурированных данных
  • Files vs Relation: Files для файлов, Relation для связей между записями