OUTPUT узла показывает результат конкретного выполнения. Если следующая схема должна прочитать его позже, данные нужно сохранить отдельно. В n8n для этого есть Data Tables — внутренние таблицы. Создадим таблицу результатов заказов, запишем три строки через Upsert и прочитаем их другим workflow, в том числе после перезапуска n8n.
Результат инструкции
В таблице ezgpt_order_results будет по одной строке последнего результата для заказов O1, O2 и O3. У O1 сумма 150000 копеек, у O2 — допустимый ноль, у ошибочного O3 — needs_review и причины проверки, а сумма пустая. Повторный последовательный запуск обновит строки по order_id, а не добавит ещё три.
Это хранилище текущих результатов, не история всех событий и не защита от одновременных записей. AI-модели, оплаты и отправки здесь нет. Статус ready означает прохождение наших учебных правил, а не разрешение автоматически списывать деньги или отправлять заказ клиенту.
Что понадобится
- Работающий n8n с доступным разделом Data tables. Сценарий проверен на n8n 2.42.4.
- Права создавать таблицы и workflows в одном своём проекте. В учебной таблице не используйте настоящие данные клиентов.
- Для локальной установки — сохраняемый том n8n. Перезапуск без сохранённого хранилища не доказывает долговечность данных.
Установка n8n через Docker с сохраняемым томом
Шаг 1. Создайте пустую Data Table
Откройте свой проект n8n и вкладку Data tables. Выберите Create Data table, затем создание From scratch. Назовите таблицу ровно ezgpt_order_results. Не создавайте её в другом проекте: оба учебных workflows должны работать с этой же таблицей.
Если Data tables отсутствует, проверьте версию и доступность функции у администратора. Не заменяйте её обычной переменной или закреплённым OUTPUT: это другой способ хранения и не повторит наш пример.
Шаг 2. Добавьте пять колонок
В созданной таблице добавьте колонки с именами и типами ниже. Для string используйте текстовый тип интерфейса, для number — числовой. Не переводите имена колонок на русский и не добавляйте в них пробелы.
| Колонка | Тип | Что хранит |
|---|---|---|
| order_id | string | ID заказа: O1, O2, O3 |
| status | string | ready или needs_review |
| amount_minor | number | Копейки; null при ошибке |
| errors_text | string | Причины проверки или пустой текст |
| validation_version | string | Учебная метка v1 |
Системные id, createdAt и updatedAt n8n добавляет сам; повторно создавать их не нужно. order_id — наш идентификатор заказа, id — идентификатор строки таблицы. Это разные поля. Мы намеренно не сохраняем имя клиента: для повторного чтения результата достаточно ID и статуса.
Шаг 3. Импортируйте схему записи
Скачать n8n-datatables-save.json
Сохраните JSON-файл, создайте новый workflow в том же проекте и выберите Import from File в меню редактора. Если браузер показывает JSON вместо скачивания, используйте «Сохранить как». Название схемы — ezGPT - Save Order Results. На полотне должно быть пять узлов.
Manual Trigger → Test Orders → Split Orders → Prepare Rows → Save Results
Test Orders — Edit Fields (Set), Split Orders — Split Out, Prepare Rows — Code, Save Results — Data table. Если собираете вручную, добавьте эти узлы в указанном порядке. Сохраните workflow ручным, без расписания и публикации.
Шаг 4. Добавьте тестовые заказы
В Test Orders выберите Mode: JSON Output и вставьте объект ниже. Один item содержит массив orders из трёх вымышленных заказов. В импортированном файле этот объект уже задан.
{
"orders": [
{
"order_id": "O1",
"client": " Анна Петрова ",
"amount_minor": "150000",
"currency": "rub"
},
{
"order_id": "O2",
"client": "Борис",
"amount_minor": 0,
"currency": "RUB"
},
{
"order_id": "O3",
"client": "",
"amount_minor": "сумма",
"currency": "RUB"
}
]
}
amount_minor — сумма в копейках, а не в рублях. Строка «150000» будет проверена и преобразована в число, 0 останется допустимым нулём. Ошибочный заказ O3 сохранится как результат проверки с пустой суммой, а не как заказ на ноль рублей.
Шаг 5. Разделите массив на записи
В Split Orders укажите Field to Split Out: orders и Include: No Other Fields. Выполните цепочку до этого узла: ожидаются три items. Поля каждого заказа должны находиться прямо в json, а не внутри orders.
Шаг 6. Подготовьте строки для таблицы
В Prepare Rows выберите Language: JavaScript, Mode: Run Once for All Items и вставьте код ниже. Он выдаёт только пять полей из структуры таблицы. Отдельная проверка всех ID выполняется до подготовки записей: пустой или повторяющийся очищенный ID останавливает всю схему до Upsert.
const rows = $input.all().map(item => item.json);
const clean = value => typeof value === 'string'
? value.trim().replace(/\s+/g, ' ') : '';
const ids = rows.map(row => clean(row.order_id));
if (ids.some(id => !id) || new Set(ids).size !== ids.length)
throw new Error('invalid_or_duplicate_order_id');
return rows.map((row, index) => {
const raw = row.amount_minor;
const amount = typeof raw === 'number' ? raw
: typeof raw === 'string' && /^\d+$/.test(raw.trim())
? Number(raw.trim()) : NaN;
const errors = [];
if (!clean(row.client)) errors.push('client_required');
if (clean(row.currency).toUpperCase() !== 'RUB')
errors.push('currency_must_be_RUB');
if (!Number.isSafeInteger(amount) || amount < 0)
errors.push('amount_minor_invalid');
return {
json: {
order_id: ids[index],
status: errors.length ? 'needs_review' : 'ready',
amount_minor: errors.length ? null : amount,
errors_text: errors.join('; '),
validation_version: 'v1',
},
pairedItem: { item: index },
};
});
Число считается допустимым только в безопасном целочисленном диапазоне и не меньше нуля. Строки должны состоять из цифр: null, «1e3» и текст о цене не преобразуются молча в сумму. У невалидного заказа amount_minor становится null, а ошибки объединяются в errors_text. validation_version — наша метка проверки, не автоматическая версия workflow.
Как работает Code и структура items в n8n
Шаг 7. Настройте Upsert по order_id
В Save Results выберите Resource: Row, Operation: Upsert. В Data table укажите By Name: ezgpt_order_results или выберите эту же таблицу From list. При выборе другой таблицы повторно проверьте её колонки.
Must Match: All Conditions. Добавьте одно условие: Column order_id, Condition Equals, Value — Expression ниже. Не используйте status вместо ID: одинаковый статус может быть у нескольких заказов.
{{ $json.order_id }}
Mapping Column Mode: Map Automatically. Все пять имён полей Prepare Rows точно совпадают с колонками. В Options оставьте Dry Run выключенным, а в Settings — On Error: Stop Workflow. Если не найдена таблица или не прошла запись, не продолжайте работу так, будто данные сохранены.
Шаг 8. Запишите и проверьте три строки
Выполните весь workflow через Manual Trigger. Затем откройте ezgpt_order_results в Data tables и при необходимости обновите таблицу. Проверяйте именно её строки, а не только OUTPUT Save Results.
- O1: status ready, amount_minor 150000, errors_text пустой, validation_version v1.
- O2: status ready, amount_minor 0, errors_text пустой, validation_version v1.
- O3: status needs_review, amount_minor пустой/null, errors_text «client_required; amount_minor_invalid», validation_version v1.
Строк должно быть три. В поле number не пишите строку «null»: код передаёт настоящее JSON-значение null. Пустая сумма у ошибочного заказа и 0 у готового должны различаться.
Шаг 9. Проверьте повтор и обновление
Повторно запустите схему с тем же JSON. В таблице должны остаться три строки, а их системные id — прежними. Upsert ищет строку по order_id; Insert каждый раз создавал бы новую запись.
Затем в Test Orders замените сумму O1 на строку «160000». Новый запуск должен изменить его сумму до 160000 копеек, сохранив id. У O2 и O3 статус, сумма и errors_text останутся прежними; служебный updatedAt может обновиться, потому что Upsert обрабатывает все три записи. Не редактируйте id вручную.
Такое поведение проверено при последовательных запусках. Наше условие Upsert не создаёт уникальный индекс на order_id и не доказывает отсутствие дублей при конкуренции. На первом этапе не запускайте параллельно несколько writers для одной таблицы.
Шаг 10. Импортируйте независимое чтение
Скачать n8n-datatables-read.json
Создайте второй новый workflow в этом же проекте и импортируйте n8n-datatables-read.json. Его имя — ezGPT - Read Order Results. Здесь только два узла:
Manual Trigger → Read Results
В Read Results выберите Resource: Row, Operation: Get, ту же Data table. Conditions оставьте пустыми, Return All включите. Выполните этот workflow отдельно: ожидаются три сохранённые строки. В нём нет Test Orders и записи, поэтому результат приходит из таблицы, а не из входного JSON первой схемы. Порядок строк не считайте гарантированным.
Шаг 11. Получите только ready
В Read Results добавьте условие Column: status, Condition: Equals, Value: обычный текст ready. Оставьте Return All включённым. Выполните чтение: должно вернуться два items с order_id O1 и O2. Запись O3 остаётся в таблице, но не попадает в отфильтрованный результат.
Верните Read Results к чтению всех строк: удалите условие status. Фильтр не удаляет данные, а Return All означает все совпавшие строки, не всегда всю таблицу. Для крупной меняющейся таблицы нужна отдельная стратегия чтения и ограничения объёма; этот пример использует три строки.
Шаг 12. Проверьте неверные данные до записи
В Test Orders схемы записи замените сумму O1 на null и запустите workflow. Таблица должна показать для O1 needs_review и amount_minor null. Это сохранённый результат неуспешной проверки данных; технической ошибки записи в данном случае нет.
Теперь восстановите исходный JSON из шага 4, выполните запись и отдельно чтение всех строк. После этого в учебной копии Test Orders поставьте пустой order_id у O1. Код должен завершиться с invalid_or_duplicate_order_id, а Save Results не должен запуститься. Существующие строки останутся прежними. Аналогично проверьте два одинаковых ID, заменив O2 на « O1 ».
Верните исходный JSON и снова запишите три корректно обработанных результата. Проверка перед Upsert защищает от этих ошибок входа, но не делает запись всего набора атомарной: при сбое хранилища уже записанные строки могут остаться. Не обещайте «всё или ничего» без отдельного механизма транзакций.
Шаг 13. Перезапустите локальный n8n и прочитайте снова
Для установки по нашей Docker-инструкции откройте PowerShell в её папке и выполните команды ниже. На другой установке используйте свой согласованный способ перезапуска. В Cloud не пытайтесь выполнять эти локальные команды; повторное чтение можно проверить без перезапуска сервиса.
Set-Location "$HOME/n8n-local"
docker compose restart n8n
docker compose ps
Дождитесь, пока редактор снова станет доступен. Откройте Read Order Results и выполните Manual Trigger. Должны вернуться те же три строки, включая нулевую сумму O2 и null у O3. Это новое выполнение, не просмотр прежнего OUTPUT.
В нашей проверке после перезапуска сохранились также системные id. Не удаляйте Docker volume и не используйте down -v для такого теста. Таблицы хранятся в данных экземпляра n8n: сохраняемый том нужен локальной установке, а резервная копия — восстановлению после потери хранилища.
Шаг 14. Проверьте Dry Run и восстановите настройки
В Save Results включите Options → Dry Run. В Test Orders временно поменяйте сумму O1 на 999000. Выполните запись, а затем независимый Read Order Results. В таблице O1 должен остаться на 150000 копеек: Dry Run показывает предполагаемые изменения, но не сохраняет их.
Не выдавайте OUTPUT Dry Run за записанные данные. Верните исходный JSON и выключите Dry Run. Снова выполните запись и чтение. Финальный результат — три строки O1/O2/O3 со значениями из шага 8; оба workflows остаются ручными и неопубликованными.
Если результат отличается
| Симптом | Причина | Что проверить |
|---|---|---|
| Table не найдена | Другой проект или имя | ezgpt_order_results в своём проекте |
| Число строк растёт | Insert вместо Upsert | Upsert с условием order_id |
| Изменения не сохранились | Включён Dry Run | Выключите его и прочитайте заново |
| Ошибка колонок | Имена или типы отличаются | Пять колонок из шага 2 |
| Ноль стал пустым | Неверное преобразование суммы | Полный код Prepare Rows |
| После перезапуска нет данных | Другое или удалённое хранилище | Том n8n и имя выбранной таблицы |
Перед подключением рабочих данных
Не храните API-ключи и пароли в Data Tables: используйте штатные credentials n8n. Участники проекта могут иметь доступ к его таблицам, поэтому сначала согласуйте права, состав данных и срок хранения. Наш учебный пример сохраняет только ID и результат проверки, без имени клиента.
Upsert перезаписывает последнее состояние заказа. Для истории всех проверок понадобится отдельная модель с идентификатором события; для полноценного аудита — согласованные правила доступа, изменения и хранения. Data Tables удобны для небольших внутренних наборов, но не заменяют проектирование производственной базы. Контролируйте доступный лимит хранения своего экземпляра.
Не связывайте status ready сразу с оплатой, удалением или отправкой сообщения. Сначала проверьте источник, обновления и ошибки хранения. Ошибка чтения не означает, что данные были удалены, а наличие трёх строк не доказывает полноту реальной выгрузки из CRM.
Что проверено редакцией
13 октября 2026 года сценарий проверен на n8n 2.42.4 в отдельном локальном экземпляре. Таблица и workflows созданы через API n8n, схемы выполнены штатным ручным запуском через API экземпляра. Одиннадцать сценариев: первая запись, повтор, обновление суммы, null, пустой ID, дубли очищенного ID, восстановление, Dry Run, отсутствующая таблица, фильтр ready и чтение после перезапуска. Значения, число строк, стабильность системных id и отсутствие изменений при ошибках входа и Dry Run проверены; отдельно проверено чтение пустой таблицы. Standalone CLI не загрузил модуль Data Tables в этой конфигурации, поэтому успешные тесты не используют CLI execution. Кликовые действия редактора, Cloud, параллельные записи, большие наборы, лимит хранения, атомарность набора и реальные CRM не тестировались. Учебный сервер был доступен только на 127.0.0.1; рабочие workflows не менялись. Обложка — редакционная AI-иллюстрация.
Частые вопросы
Data Tables используют AI и расходуют токены?
Нет. Эта схема выполняет обычную проверку и запись в таблицу n8n. AI-модель и её API-ключ не нужны.
Чем таблица отличается от OUTPUT?
OUTPUT относится к конкретному выполнению. Data Table хранит отдельные строки, которые другой workflow читает в новом запуске. В локальной установке сохраняйте данные экземпляра и резервные копии.
Почему Upsert, а не Insert?
Нужен последний результат для каждого order_id. Upsert обновляет совпавшую строку, а Insert добавляет новую. Это не гарантирует уникальность при одновременных запусках и не хранит историю всех изменений.
Почему у ошибочного заказа сумма null, а не 0?
Ноль — известная допустимая сумма по нашим учебным правилам. null означает, что проверка не разрешила использовать сумму. Статус и errors_text объясняют причину; не превращайте неизвестное значение в ноль.
Можно ли положить туда API-ключи и данные клиентов?
Ключи храните в credentials. Для клиентских данных сначала согласуйте минимальный состав, права участников проекта, срок хранения и резервное копирование. Учебный JSON не является разрешением хранить реальные персональные данные.