Форма прислала budget строкой, имя с пробелами, а вместе с нужными полями пришла внутренняя пометка. Перед API такой набор лучше привести к понятному формату. В n8n это можно сделать узлом Edit Fields (Set): выбрать поля, переименовать их, задать типы и собрать вложенный объект. Пройдём весь путь на трёх вымышленных заявках.
Результат инструкции
На входе будут три отдельных items. На выходе останутся три items, каждый со своим payload: request_id, вложенный contact с именем и email, числовой budget_minor, логический consent и источник website. Нулевой бюджет останется нулём, строка false станет логическим false. Внутренняя пометка в payload не попадёт.
Мы не отправляем данные клиентам и не вызываем внешний API. Последний Code проверяет результат и добавляет action_performed: false. Это учебный договор о структуре данных, а не готовый формат произвольной CRM. AI-модель для переименования полей не нужна.
Что понадобится
- Работающий n8n и возможность создать отдельный workflow. Проверено на n8n 2.42.4, Edit Fields версии 3.4.
- Три вымышленные заявки из примера. Адреса example.invalid не предназначены для доставки писем.
- API-ключи, платные сервисы и реальные данные клиентов не нужны.
Установка n8n локально через Docker
Шаг 1. Импортируйте учебный workflow
Скачать n8n-edit-fields-leads.json
Создайте новый workflow и выберите Import from File в меню редактора. Загрузите JSON. Если браузер открыл файл текстом, сохраните его и импортируйте. На полотне должны появиться пять узлов:
Manual Trigger → Sample Leads → Validate Leads → Prepare Payload → Check Payload
Prepare Payload — Edit Fields (Set), остальные три обрабатывающих узла — Code. Для ручной сборки используйте эти же имена и соедините узлы последовательно. В файле нет credentials и ID чужого workflow. Схема не активирована; ручному тесту публикация не нужна.
Шаг 2. Подготовьте исходные заявки
В Sample Leads выберите Mode: Run Once for All Items и Language: JavaScript. Удалите стандартный код и вставьте:
const leads = [
{
"id": "L1",
"name": " Анна ",
"email": " ANNA@EXAMPLE.INVALID ",
"budget": "150000",
"consent": "true",
"internal_note": "Учебная пометка A"
},
{
"id": "L2",
"name": "Борис",
"email": "BORIS@example.invalid",
"budget": "0",
"consent": "false",
"internal_note": "Учебная пометка B"
},
{
"id": "L3",
"name": "Альфа",
"email": "team@example.invalid",
"budget": " 49900 ",
"consent": "true",
"internal_note": "Учебная пометка C"
}
];
if (!leads.length) throw new Error("leads_empty");
return leads.map(json => ({ json }));
Запустите источник от Manual Trigger. В Output ожидаются три items с ID L1, L2 и L3. Обратите внимание: budget и consent здесь строки в кавычках. У L2 бюджет "0" и согласие "false". Пробелы у имени L1 и бюджета L3 оставлены намеренно. internal_note — вымышленное поле для проверки отбора.
Шаг 3. Проверьте вход до преобразования
Откройте Validate Leads, задайте Run Once for All Items и JavaScript. Вставьте код:
const items = $input.all();
const ids = new Set();
for (const { json: row } of items) {
if (typeof row.id !== 'string' || !row.id.trim() || ids.has(row.id)) {
throw new Error('id_missing_or_duplicate');
}
if (typeof row.name !== 'string' || !row.name.trim()) throw new Error('name_required');
if (typeof row.email !== 'string' || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(row.email.trim())) {
throw new Error('email_invalid');
}
if (typeof row.budget !== 'string' || !/^\d+$/.test(row.budget.trim()) ||
!Number.isSafeInteger(Number(row.budget.trim()))) throw new Error('budget_invalid');
if (!['true', 'false'].includes(row.consent)) throw new Error('consent_invalid');
ids.add(row.id);
}
return items;
В Settings оставьте On Error: Stop Workflow и выключенный Execute Once. Код требует непустые уникальные ID, имена, email подходящей формы, целые неотрицательные копейки строкой и строго true/false строкой. Пробелы вокруг бюджета допустимы; пустая строка, null, дробь и отрицательное число — нет.
Регулярное выражение email проверяет только форму адреса, не существование ящика и не возможность доставки. consent — вымышленный флаг примера: его преобразование не подтверждает законность реальной рассылки. Проверка не меняет входные записи, а пропускает их дальше либо останавливает запуск.
Шаг 4. Выберите ручное сопоставление полей
В Prepare Payload выберите Mode: Manual Mapping. Переключатель Include Other Input Fields оставьте выключенным: в выход должны попасть только назначенные поля. В старых версиях встречается другой интерфейс, в том числе Keep Only Set Fields; ориентируйтесь на проверенную версию и смысл настройки, а не на одинаковое положение переключателя.
В Options включите Support Dot Notation и оставьте Ignore Type Conversion Errors выключенным. В Settings задайте On Error: Stop Workflow. Execute Once и Always Output Data не включайте. Для нашей задачи не нужны дублирование items или бинарные файлы.
Шаг 5. Добавьте шесть назначений
В Fields to Set создайте шесть строк. Имя поля вводится обычным текстом. Для первых пяти значений включите Expression; source оставьте Fixed. Выберите тип каждой строки отдельно:
| Имя поля | Тип | Значение |
|---|---|---|
| request_id | String | {{ $json.id }} |
| contact.name | String | {{ $json.name.trim() }} |
| contact.email | String | {{ $json.email.trim().toLowerCase() }} |
| budget_minor | Number | {{ Number($json.budget.trim()) }} |
| consent | Boolean | {{ $json.consent === 'true' }} |
| source | String, Fixed | website |
В редактор вставляйте выражения из таблицы с двойными фигурными скобками, без кавычек вокруг всего выражения. При экспорте n8n добавляет в JSON служебный начальный знак =. В готовом файле он уже есть; вручную дописывать его к видимому выражению не требуется. Проверяйте предпросмотр, а не только текст поля.
Шаг 6. Проверьте числа и логические значения
Входной budget мы договорились хранить в копейках строкой. Number преобразует "150000" в число 150000, а "0" в 0. До преобразования Validate Leads отклоняет пустоту и неверный формат, поэтому пустая строка не будет молча принята за нулевой бюджет. Значение 150000 означает 1500 рублей, не 150000 рублей.
Для consent сравнивайте строку с true. Не используйте Boolean($json.consent): в JavaScript непустая строка false тоже даёт true. Наше сравнение даёт нужный результат:
// Объяснение выражения, не отдельный узел workflow.
'false' === 'true' // false
Boolean('false') // true
Number('0') // 0
Это правило предназначено только для согласованного входа из шага 2. Если реальный сервис присылает consent логическим значением либо budget уже числом, сначала измените входной договор и Validate Leads. Не включайте игнорирование ошибок, чтобы случайно принять оба формата.
Шаг 7. Проверьте вложенный contact
При включённом Support Dot Notation имена contact.name и contact.email создают один объект contact с двумя полями. Это не две строки с точками в названиях ключей. Откройте JSON в Output Prepare Payload и убедитесь, что name и email находятся внутри contact.
Имя Анна должно быть без внешних пробелов, email — anna@example.invalid. Lowercase выбран для учебного набора; это не универсальное правило обработки всех email-адресов. Для реальной интеграции согласуйте нормализацию с требованиями её системы.
Шаг 8. Добавьте проверку результата
В Check Payload задайте Run Once for All Items и JavaScript. Вставьте код:
const items = $input.all();
const source = $('Validate Leads').all().map(item => item.json);
const keys = value => Object.keys(value).sort().join('|');
if (items.length !== source.length) throw new Error('payload_count_mismatch');
return items.map((item, i) => {
const row = item.json;
const input = source[i];
if (keys(row) !== 'budget_minor|consent|contact|request_id|source' ||
!row.contact || typeof row.contact !== 'object' || Array.isArray(row.contact) ||
keys(row.contact) !== 'email|name') throw new Error('payload_fields_mismatch');
if (row.request_id !== input.id || row.contact.name !== input.name.trim() ||
row.contact.email !== input.email.trim().toLowerCase() ||
row.budget_minor !== Number(input.budget.trim()) ||
row.consent !== (input.consent === 'true') || row.source !== 'website') {
throw new Error('payload_value_mismatch');
}
return { json: { payload: row, action_performed: false }, pairedItem: { item: i } };
});
Проверка сверяет количество записей, порядок, точный набор верхних полей и ключей contact, затем значения и типы. Если включить перенос всех входных полей, отключить dot notation или потерять source, запуск не выдаст результат за правильный. Значения сравниваются с исходными items из Validate Leads по позиции.
Схема рассчитана на один последовательный входной набор без Merge, фильтрации и перестановки между этими узлами. При изменении маршрута нужно пересмотреть сопоставление записей. В Settings оставьте Stop Workflow.
Шаг 9. Запустите всю цепочку
Нажмите Execute Workflow. В Prepare Payload ожидаются 3 items. В Check Payload тоже 3, но каждый обёрнут в payload и снабжён action_performed: false. Например, второй item должен выглядеть так:
{
"payload": {
"request_id": "L2",
"contact": {
"name": "Борис",
"email": "boris@example.invalid"
},
"budget_minor": 0,
"consent": false,
"source": "website"
},
"action_performed": false
}
Для L1 ожидаются имя Анна, email anna@example.invalid, бюджет 150000 и consent true. Для L3 — Альфа, team@example.invalid, бюджет 49900 и consent true. У всех source website. Не должно быть исходных id, name, email, budget, internal_note на верхнем уровне payload.
| Заявка | Бюджет в копейках | consent на выходе |
|---|---|---|
| L1 | 150000, Number | true, Boolean |
| L2 | 0, Number | false, Boolean |
| L3 | 49900, Number | true, Boolean |
Шаг 10. Проверьте защиту от лишних полей
В Prepare Payload временно включите Include Other Input Fields и запустите всю цепочку. В Output этого узла появятся исходные поля, включая internal_note. Check Payload должен остановиться с payload_fields_mismatch. Верните переключатель в выключенное состояние и снова выполните workflow.
Зелёный статус Edit Fields сам по себе не доказывает соответствие формату API. Он означает, что узел выполнил свою настройку. Проверка после него нужна именно для обнаружения не той настройки. Исключение internal_note из payload не удаляет его из Sample Leads, Validate Leads и сохранённых executions.
Шаг 11. Проверьте ошибочный вход и настройку
В Sample Leads у первой заявки временно замените budget на "abc". Запуск должен остановиться в Validate Leads с budget_invalid. Попробуйте "", null и "12.5": это тоже ошибки нашего входного договора. Верните "150000". Строка "0" должна проходить.
Теперь в Prepare Payload временно выключите Support Dot Notation. В выходе появятся буквальные ключи contact.name и contact.email, а Check Payload даст payload_fields_mismatch. Верните опцию. Замена значения source на other должна дать payload_value_mismatch. После каждого опыта возвращайте исходную настройку и запускайте всю цепочку заново.
Шаг 12. Сохраните рабочий результат
Верните три исходные заявки, шесть назначений, Include Other Input Fields off, Support Dot Notation on и source website. Сохраните и выполните весь workflow. Сверьте все три payload, особенно ноль и false у L2, вложенность contact и отсутствие внутренней пометки.
На этом прототип завершён. Если затем подключать HTTP Request, в тело запроса обычно понадобится конкретный объект payload текущего item, а не служебная обёртка вместе с action_performed. Сначала изучите договор конкретного API и проверьте запрос на его тестовом окружении. Этот материал не проверяет отправку, авторизацию или создание записи в CRM.
Если результат отличается
| Симптом | Причина | Что проверить |
|---|---|---|
| В значении виден текст {{ $json.id }} | Поле осталось Fixed | Expression и предпросмотр request_id |
| contact.name стал ключом с точкой | Dot notation выключен | Support Dot Notation |
| В payload осталось internal_note | Переносятся входные поля | Include Other Input Fields off |
| Ноль приняли за пустое значение | Проверка по истинности | Числовой тип и явная проверка |
| budget_invalid или consent_invalid | Вход другого формата | Строгий договор в Validate Leads |
Что не делает эта схема
Edit Fields меняет представление текущего item, а не группирует записи в массив и не очищает внешнюю базу. Здесь три входные заявки остаются тремя выходными. Чтобы собрать один массив, используется Aggregate. Для разбора входящего массива — Split Out.
Собрать записи в один массив через Aggregate
Разделить JSON-массив на отдельные items
Не отправляйте реальные заявки и письма сразу после учебного теста. Нужны отдельные правила прав доступа, хранения истории, согласий, повторных запросов и обработки ответа принимающей системы. Отбор выходных полей не заменяет эти проверки.
Что проверено редакцией
15 октября 2026 года workflow проверен на n8n 2.42.4 в отдельном Docker-экземпляре через штатные ручные запуски API. Все 22 проверки прошли: три заявки, одна, обратный порядок, дополнительное поле, пустой источник, текстовый/пустой/null/отсутствующий/отрицательный/дробный/слишком большой бюджет, повтор ID, пустое имя, неверный email, неверное согласие, логический вход вместо строки, перенос всех входных полей, отключение dot notation, текст вместо выражения, потеря поля и неправильный source. Сверены точные payload, типы, вложенность, количество и отсутствие успешного результата при ошибках. Настройки сверены с официальной документацией и кодом штатного Edit Fields версии 3.4. Редакторские клики, n8n Cloud, бинарные файлы, большие объёмы, внешние API и доставка писем не тестировались. Учебный контейнер остановлен, существующие workflows не менялись. Обложка — редакционная AI-иллюстрация.
Частые вопросы
Edit Fields и Set — разные узлы?
В этой инструкции это один узел Edit Fields (Set). В экспортированном workflow его тип n8n-nodes-base.set. Интерфейс и набор параметров зависят от версии; пример использует 3.4.
Почему после узла осталось три items?
Узел подготовил поля отдельно для каждой заявки. Он не собирает записи в один массив. Для одного item с массивом нужен Aggregate и другая проверка результата.
Почему строку false нельзя преобразовать через Boolean?
Непустая строка false даёт true. Для согласованного строкового входа мы используем точное сравнение с true, а остальные варианты отклоняем до преобразования.
Выключение Include Other Input Fields удаляет данные из истории?
Нет. Оно ограничивает текущий выход узла. Исходные поля могут оставаться в предыдущих узлах и сохранённых executions. Доступ и сроки хранения настраиваются отдельно.
Можно ли сразу подключить CRM?
Сначала сопоставьте payload с полями и типами конкретного API, проверьте тестовый запрос, права, повторные вызовы и ответ. Учебный workflow ничего во внешнюю систему не записывает.