Пошаговые инструкции Для начинающих 13 мин

Compare Datasets в n8n: как сравнить две выгрузки по ID

Найдите новые, изменённые и пропавшие записи между двумя снимками. 12 шагов, готовый workflow, пустые выгрузки и проверка дублей.

n8n Compare Datasets Сравнение данных

В новой выгрузке один заказ появился, другой пропал, у третьего изменилась сумма. Сравнивать строки по их месту в файле нельзя: порядок мог поменяться. В этой инструкции сопоставим записи по ID и получим четыре отдельных результата через штатный Compare Datasets в n8n.

Результат инструкции

Соберём ручной workflow на двух вымышленных снимках заказов. Старую выгрузку подключим к Input A, новую — к Input B. Сопоставлять будем по order_id. В конце увидим записи только в A, одинаковые записи, изменения и записи только в B. Никаких обновлений или удалений в базе схема не выполняет.

Результат находится в четырёх выходах Compare Datasets, а не в одном сводном JSON. Для основного примера в каждом выходе будет по одной записи. Изменённый заказ сохранит старое и новое значение суммы, включая исходный ноль. AI-модель и API-ключи не нужны.

Что понадобится

  • Работающий n8n и доступ к новому учебному workflow. Проверено на n8n 2.42.4 и Compare Datasets версии 2.3.
  • Code на JavaScript для подготовки и проверки входа. Реальные CRM, таблицы и базы подключать не нужно.
  • Договор данных: order_id — строка из трёх цифр, name — непустой текст, amount_minor — целое неотрицательное число копеек.

Установить n8n локально через Docker

Шаг 1. Импортируйте готовую схему

Скачать n8n-compare-snapshots.json

Создайте отдельный workflow. В меню редактора выберите Import from File и загрузите JSON. В схеме шесть узлов и две ветки после Check Snapshots:

text
Manual Trigger → Sample Snapshots → Check Snapshots
Check Snapshots → Before Rows → Compare Snapshots [Input A]
Check Snapshots → After Rows  → Compare Snapshots [Input B]

Compare Snapshots — штатный Compare Datasets. Остальные узлы кроме триггера — Code. Workflow неактивен, credentials и ID чужой схемы не содержит. Не добавляйте узлы удаления, обновления CRM и отправки отчёта: сначала проверим само сравнение.

Шаг 2. Подготовьте старую и новую выгрузки

Скачать учебные данные n8n-compare-demo.json

Файл дан для сверки, автоматически узлом не загружается. В Sample Snapshots выберите Mode: Run Once for All Items, Language: JavaScript. Вставьте:

javascript
const before = [
  {"order_id":"001","name":"Альфа","amount_minor":150000},
  {"order_id":"002","name":"Бета","amount_minor":0},
  {"order_id":"003","name":"Гамма","amount_minor":50000}
];
const after = [
  {"order_id":"001","name":"Альфа","amount_minor":150000},
  {"order_id":"002","name":"Бета","amount_minor":20000},
  {"order_id":"004","name":"Дельта","amount_minor":70000}
];
return [{ json: { before, after } }];

Выполните источник от Manual Trigger. Ожидается один item с массивами before и after. В каждом массиве три заказа. ID 001 — строка с ведущими нулями, сумма у 002 в старом снимке — число 0. По данным должно получиться:

ID В старом снимке В новом снимке
001 Альфа, 150000 копеек Альфа, 150000 копеек
002 Бета, 0 копеек Бета, 20000 копеек
003 Гамма, 50000 копеек Нет
004 Нет Дельта, 70000 копеек

Сопоставляем по order_id, а не по имени клиента: у одного клиента могут быть разные заказы. Для реального источника сначала определите надёжный ключ. В этой инструкции значение ID уникально внутри каждого снимка, но один и тот же ID закономерно встречается в обоих.

Шаг 3. Проверьте оба снимка до сравнения

В Check Snapshots задайте Run Once for All Items, JavaScript и вставьте:

javascript
const items = $input.all();
if (items.length !== 1) throw new Error('one_snapshot_item_required');
const source = items[0].json;
for (const side of ['before', 'after']) {
  const rows = source[side];
  if (!Array.isArray(rows)) throw new Error(side + '_array_required');
  if (rows.length > 20) throw new Error(side + '_too_many_rows');
  const ids = new Set();
  for (const row of rows) {
    if (!row || typeof row !== 'object' || Array.isArray(row) || Object.keys(row).sort().join('|') !== 'amount_minor|name|order_id') {
      throw new Error(side + '_row_fields_invalid');
    }
    if (typeof row.order_id !== 'string' || !/^\d{3}$/.test(row.order_id) || ids.has(row.order_id)) {
      throw new Error(side + '_id_invalid_or_duplicate');
    }
    if (typeof row.name !== 'string' || !row.name.trim()) throw new Error(side + '_name_required');
    if (!Number.isSafeInteger(row.amount_minor) || row.amount_minor < 0) {
      throw new Error(side + '_amount_invalid');
    }
    ids.add(row.order_id);
  }
}
return [{ json: { before: source.before, after: source.after } }];

Проверка допускает пустой массив, но отклоняет null, объект вместо массива, больше 20 записей и повтор ID в одном снимке. В каждой записи должны быть ровно три согласованных поля. Текстовая сумма, отрицательное число, дробные копейки и число вне безопасного целочисленного диапазона не пройдут.

Двадцать записей — выбранный учебный лимит, не ограничение Compare Datasets. Для реальной выгрузки отдельно согласуйте набор полей: техническое updated_at не должно случайно становиться бизнес-изменением, но удалять его из сравнения без понимания тоже нельзя.

В Settings всех узлов оставьте On Error: Stop Workflow. Always Output Data, Continue On Fail, Retry On Fail и Execute Once не включайте. При нарушении договора нельзя переходить к сравнению неполных или неоднозначных записей.

Шаг 4. Превратите старый снимок в items

В Before Rows выберите Run Once for All Items, JavaScript и вставьте:

javascript
const rows = $input.first().json.before;
return rows.length ? rows.map(json => ({ json })) : [{ json: {} }];

Для основного примера узел выдаст три items, по одному заказу в каждом. Это важное преобразование: Compare Datasets должен получать отдельные записи, а не один объект с вложенным массивом before.

Для пустого массива код выдаёт один технический пустой объект. Он нужен, чтобы ветка выполнилась и дошла до сравнения. В проверенной версии 2.3 Compare Datasets исключает такой пустой объект из данных. В результирующих выходах он не должен появляться как заказ.

Шаг 5. Подготовьте новый снимок и подключите входы

В After Rows задайте Run Once for All Items, JavaScript и вставьте:

javascript
const rows = $input.first().json.after;
return rows.length ? rows.map(json => ({ json })) : [{ json: {} }];

Соедините выход Check Snapshots с обоими Code-узлами. Выход Before Rows подключите именно к Input A узла Compare Snapshots, выход After Rows — к Input B. У Compare Datasets два отдельных входа; подключение обеих веток к одному входу не соответствует нашей задаче.

После полного запуска Before Rows и After Rows должны выдавать по три items. Для пустой ветки ожидается один технический пустой объект до Compare, но ноль записей после его фильтрации. Работа с пустыми снимками проверена отдельно, включая случай, когда оба массива пустые.

Шаг 6. Настройте сопоставление по ID

В Compare Snapshots в Fields to Match добавьте одну пару: Input A Field — order_id, Input B Field — order_id. Введите имена полей как обычный текст, не как выражения со значением конкретного заказа.

Сначала узел находит записи с одинаковым ключом, затем сравнивает их остальные поля. Если вместо order_id сопоставить name с order_id, нужные пары не найдутся: заказы могут разойтись в выходы только A и только B, хотя выполнение завершится успешно. Зелёного статуса недостаточно.

Не добавляйте amount_minor в Fields to Match для этой задачи. Иначе изменившаяся сумма может помешать найти пару одного и того же заказа. Ключ отвечает на вопрос «это та же запись?», остальные поля — на вопрос «что у неё изменилось?».

Шаг 7. Сохраните обе версии изменения

В When There Are Differences выберите Include Both Versions. Fuzzy Compare оставьте Off. В Options задайте Multiple Matches: Include First Match Only, Fields to Skip Comparing оставьте пустым, Disable Dot Notation — Off.

Мы явно задали режим, а не полагаемся на настройки по умолчанию. Повторы ID всё равно отклоняются раньше в Check Snapshots: Include First Match Only не используется как способ молча убрать дубли. Суммы и типы должны соответствовать договору до сравнения.

Не добавляйте amount_minor в Fields to Skip Comparing. В нашем тесте это скрыло единственное изменение заказа 002, и он попал в Same. Для реального процесса пропускайте только поля, которые действительно не влияют на требуемое сравнение.

Шаг 8. Выполните схему и откройте четыре выхода

Нажмите Execute Workflow. Откройте Output узла Compare Snapshots и последовательно просмотрите четыре именованных выхода. В основном примере ожидается:

Выход Число записей Что должно быть
In A only 1 003: нет в новой выгрузке
Same 1 001: данные совпали
Different 1 002: сумма 0 → 20000
In B only 1 004: новая запись

Same для заказа 001 содержит исходный объект старого снимка:

json
{
  "order_id": "001",
  "name": "Альфа",
  "amount_minor": 150000
}

Здесь четыре результата относятся к разным выходам одного узла, не к четырём items одного общего массива. Не подключайте все выходы к одному следующему действию без сохранения смысла ветки. Эта инструкция заканчивается просмотром различий.

Шаг 9. Разберите изменённую запись

В выходе Different у заказа 002 ожидается такой объект:

json
{
  "keys": {
    "order_id": "002"
  },
  "same": {
    "order_id": "002",
    "name": "Бета"
  },
  "different": {
    "amount_minor": {
      "inputA": 0,
      "inputB": 20000
    }
  }
}

keys содержит ключ сопоставления. same — поля, которые совпали, включая ID и имя. В different.amount_minor.inputA лежит старая сумма 0, в inputB — новая 20000. Это значения в копейках; 20000 копеек — 200 рублей.

Include Both Versions не выбирает победителя и не обновляет систему. Если переключиться на Use Input B Version, Different будет содержать новую запись без такого подробного сравнения. Для нашей инструкции сохраните обе версии, чтобы видеть, откуда и куда изменилось значение.

Шаг 10. Проверьте независимость от порядка строк

В Sample Snapshots временно переставьте строки в обоих массивах в обратном порядке. Выполните всю схему. Заказ 001 должен остаться в Same, 002 — в Different, 003 — только в A, 004 — только в B. Мы сравниваем ключи, а не позиции.

Верните порядок. Затем временно сделайте after точной копией before. Ожидаются три записи в Same и ноль в остальных выходах. Нулевое количество Different в таком тесте — правильный результат, не ошибка. После проверки верните исходный after из шага 2.

Шаг 11. Проверьте пустые выгрузки

Временно задайте before пустым массивом [], сохранив исходный after. Ожидаются три записи только в B, а остальные выходы пустые. Затем верните before и сделайте after пустым: три записи должны оказаться только в A.

Если оба массива пустые, все четыре выхода должны содержать ноль записей. Compare Snapshots при этом должен выполниться, а технические пустые объекты из Before Rows и After Rows не должны попасть в результат. После теста восстановите оба массива.

Пустой массив и недоступная выгрузка — не одно и то же. Код принимает [] как явно переданный пустой снимок, но отклоняет null и объект. В реальной интеграции нельзя превращать сетевую ошибку или обрезанную пагинацию в «новая база пуста». Проверку полноты источника нужно сделать до этого workflow.

Шаг 12. Проверьте дубли и восстановите настройки

В Sample Snapshots временно добавьте в before вторую запись с order_id 001. Check Snapshots должен остановиться с before_id_invalid_or_duplicate ещё до сравнения. Удалите дубль. Если заменить amount_minor нового заказа на строку, например "20000", ожидается after_amount_invalid, а не приблизительное сравнение.

Проверьте направление A/B: если поменять входы местами, старое и новое значение в Different тоже поменяются местами, а записи 003 и 004 окажутся в противоположных выходах. Верните Before Rows к A и After Rows к B.

Сохраните исходные данные, order_id с обеих сторон, Include Both Versions, Fuzzy Compare Off и пустой Fields to Skip Comparing. Выполните ещё раз и сверьте все четыре выхода с шагом 8. В схеме по-прежнему не должно быть действий записи или удаления данных.

Если результат отличается

Симптом Что проверить Ожидаемое условие
before_id_invalid_or_duplicate ID старого снимка Уникальная строка из трёх цифр
after_amount_invalid Тип и значение новой суммы Безопасное целое число копеек
Всё только в A и B Fields to Match order_id с обеих сторон
002 попал в Same Fields to Skip Comparing amount_minor не пропущен
Новые и пропавшие перепутаны Подключение входов Старое A, новое B

Почему In A only не означает «удалить»

Заказ может отсутствовать в новой выгрузке из-за фильтра, прав доступа, диапазона дат, ошибки API или неполной загрузки страниц. Наш пример сравнивает переданные снимки, но не доказывает полноту новой выгрузки. Выход In A only — повод проверить причину, не разрешение на удаление заказа в CRM.

Прототип не записывает историю, не синхронизирует системы и не разрешает конфликты за пользователя. Перед автоматическими изменениями нужны подтверждение полноты данных, правила приоритетов, журнал действий и возможность восстановления. Дубли ID нельзя скрывать произвольным выбором первой записи.

Прочитать CSV и проверить типы полей

Убрать дубли по согласованному ключу

Остановить workflow при неверных данных

Что проверено редакцией

17 октября 2026 года workflow проверен на n8n 2.42.4 в отдельном Docker-экземпляре ручными запусками API. Все 35 тестов прошли: основной пример, порядок строк, одинаковые и полностью разные записи, отсутствие общих ID, пустые снимки, одна запись, изменения имени и суммы, нули, дубли и неверные поля, типы и размеры. Отдельно проверены перепутанные входы, пропуск суммы, неверный ключ, выбор версии B и отсутствие пары сопоставления. Сверены точные данные всех четырёх выходов, обе версии изменения и отсутствие технических пустых записей. Основной запуск использует точный скачиваемый workflow. Compare Datasets 2.3 выполнялся один раз за запуск. Настройки сверены с официальной документацией и кодом узла. Редакторские клики, Cloud, реальные источники, пагинация, большие объёмы, запись в базы и удаление не тестировались. Учебный контейнер остановлен, существующие workflows не менялись. Обложка — редакционная AI-иллюстрация, не снимок реального интерфейса.

Частые вопросы

Почему нельзя сравнивать по номеру строки?

Порядок строк в двух выгрузках может отличаться. В примере записи сопоставляются по order_id, поэтому перестановка строк не меняет их принадлежность к выходам.

Где один итоговый JSON со всеми изменениями?

В этой схеме его нет. Штатный Compare Datasets возвращает четыре отдельных выхода: только A, одинаковые, разные и только B. Их нужно проверять по отдельности.

Зачем отклонять дубли, если есть Multiple Matches?

Режим выбора совпадений не объяснит, какая из конфликтующих записей правильная. В этой инструкции договор требует один ID на запись внутри каждого снимка, поэтому дубли останавливают сравнение.

Что получится, если новая выгрузка пустая?

Все старые записи окажутся в In A only. Это правильно для переданных данных, но не подтверждает, что источник действительно пуст: сначала нужно исключить ошибку загрузки и неполную выгрузку.

Можно автоматически удалять записи из In A only?

Не по этой инструкции. Отсутствие в снимке не доказывает необходимость удаления. Сначала проверьте полноту данных и правила процесса, затем предусмотрите подтверждение и восстановление.

Дальше по теме

Похожие материалы