mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
feat(Filter Node): New node
This commit is contained in:
parent
5dda3f2c61
commit
cc9fe7b91f
19
packages/nodes-base/nodes/Filter/Filter.node.json
Normal file
19
packages/nodes-base/nodes/Filter/Filter.node.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"node": "n8n-nodes-base.filter",
|
||||||
|
"nodeVersion": "1.0",
|
||||||
|
"codexVersion": "1.0",
|
||||||
|
"details": "The Filter node can be used to filter items based on a condition. If the condition is met, the item will be passed on to the next node. If the condition is not met, the item will be omited. Conditions can be combined together by AND(meet all conditions), or OR(meet at least one condition).",
|
||||||
|
"categories": ["Core Nodes"],
|
||||||
|
"resources": {
|
||||||
|
"primaryDocumentation": [
|
||||||
|
{
|
||||||
|
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.filter/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"generic": []
|
||||||
|
},
|
||||||
|
"alias": ["Router", "Filter", "Condition", "Logic", "Boolean", "Branch"],
|
||||||
|
"subcategories": {
|
||||||
|
"Core Nodes": ["Flow"]
|
||||||
|
}
|
||||||
|
}
|
360
packages/nodes-base/nodes/Filter/Filter.node.ts
Normal file
360
packages/nodes-base/nodes/Filter/Filter.node.ts
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
import type {
|
||||||
|
IExecuteFunctions,
|
||||||
|
INodeExecutionData,
|
||||||
|
INodeParameters,
|
||||||
|
INodeType,
|
||||||
|
INodeTypeDescription,
|
||||||
|
NodeParameterValue,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import { compareOperationFunctions, convertDateTime } from './GenericFunctions';
|
||||||
|
|
||||||
|
export class Filter implements INodeType {
|
||||||
|
description: INodeTypeDescription = {
|
||||||
|
displayName: 'Filter',
|
||||||
|
name: 'filter',
|
||||||
|
icon: 'fa:filter',
|
||||||
|
group: ['transform'],
|
||||||
|
version: 1,
|
||||||
|
description: 'Filter out incoming items based on given conditions',
|
||||||
|
defaults: {
|
||||||
|
name: 'Filter',
|
||||||
|
color: '#229eff',
|
||||||
|
},
|
||||||
|
inputs: ['main'],
|
||||||
|
outputs: ['main'],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Conditions',
|
||||||
|
name: 'conditions',
|
||||||
|
placeholder: 'Add Condition',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: true,
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
description: 'The type of values to compare',
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'boolean',
|
||||||
|
displayName: 'Boolean',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Value 1',
|
||||||
|
name: 'value1',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
|
||||||
|
description: 'The value to compare with the second one',
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line n8n-nodes-base/node-param-operation-without-no-data-expression
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Equal',
|
||||||
|
value: 'equal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Equal',
|
||||||
|
value: 'notEqual',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'equal',
|
||||||
|
description: 'Operation to decide where the the data should be mapped to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value 2',
|
||||||
|
name: 'value2',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
|
||||||
|
description: 'The value to compare with the first one',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'dateTime',
|
||||||
|
displayName: 'Date & Time',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Value 1',
|
||||||
|
name: 'value1',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
description: 'The value to compare with the second one',
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line n8n-nodes-base/node-param-operation-without-no-data-expression
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Occurred After',
|
||||||
|
value: 'after',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Occurred Before',
|
||||||
|
value: 'before',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'after',
|
||||||
|
description: 'Operation to decide where the the data should be mapped to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value 2',
|
||||||
|
name: 'value2',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
description: 'The value to compare with the first one',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'number',
|
||||||
|
displayName: 'Number',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Value 1',
|
||||||
|
name: 'value1',
|
||||||
|
type: 'number',
|
||||||
|
default: 0,
|
||||||
|
description: 'The value to compare with the second one',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
// eslint-disable-next-line n8n-nodes-base/node-param-options-type-unsorted-items
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Smaller',
|
||||||
|
value: 'smaller',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Smaller or Equal',
|
||||||
|
value: 'smallerEqual',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Equal',
|
||||||
|
value: 'equal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Equal',
|
||||||
|
value: 'notEqual',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Larger',
|
||||||
|
value: 'larger',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Larger or Equal',
|
||||||
|
value: 'largerEqual',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Is Empty',
|
||||||
|
value: 'isEmpty',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Is Not Empty',
|
||||||
|
value: 'isNotEmpty',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'smaller',
|
||||||
|
description: 'Operation to decide where the the data should be mapped to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value 2',
|
||||||
|
name: 'value2',
|
||||||
|
type: 'number',
|
||||||
|
displayOptions: {
|
||||||
|
hide: {
|
||||||
|
operation: ['isEmpty', 'isNotEmpty'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: 0,
|
||||||
|
description: 'The value to compare with the first one',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'string',
|
||||||
|
displayName: 'String',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Value 1',
|
||||||
|
name: 'value1',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'The value to compare with the second one',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
// eslint-disable-next-line n8n-nodes-base/node-param-options-type-unsorted-items
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Contains',
|
||||||
|
value: 'contains',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Contains',
|
||||||
|
value: 'notContains',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Ends With',
|
||||||
|
value: 'endsWith',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Ends With',
|
||||||
|
value: 'notEndsWith',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Equal',
|
||||||
|
value: 'equal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Equal',
|
||||||
|
value: 'notEqual',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Regex Match',
|
||||||
|
value: 'regex',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Regex Not Match',
|
||||||
|
value: 'notRegex',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Starts With',
|
||||||
|
value: 'startsWith',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Starts With',
|
||||||
|
value: 'notStartsWith',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Is Empty',
|
||||||
|
value: 'isEmpty',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Is Not Empty',
|
||||||
|
value: 'isNotEmpty',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'equal',
|
||||||
|
description: 'Operation to decide where the the data should be mapped to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value 2',
|
||||||
|
name: 'value2',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
hide: {
|
||||||
|
operation: ['isEmpty', 'isNotEmpty', 'regex', 'notRegex'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'The value to compare with the first one',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Regex',
|
||||||
|
name: 'value2',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['regex', 'notRegex'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
placeholder: '/text/i',
|
||||||
|
description: 'The regex which has to match',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Combine Conditions',
|
||||||
|
name: 'combineConditions',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'AND',
|
||||||
|
description: 'Items are passed to the next node only if they meet all the conditions',
|
||||||
|
value: 'AND',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'OR',
|
||||||
|
description: 'Items are passed to the next node if they meet at least one condition',
|
||||||
|
value: 'OR',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'AND',
|
||||||
|
description:
|
||||||
|
'How to combine the conditions: AND requires all conditions to be true, OR requires at least one condition to be true',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||||
|
const returnData: INodeExecutionData[] = [];
|
||||||
|
|
||||||
|
const items = this.getInputData();
|
||||||
|
|
||||||
|
const dataTypes = ['boolean', 'dateTime', 'number', 'string'];
|
||||||
|
|
||||||
|
itemLoop: for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
||||||
|
const item = items[itemIndex];
|
||||||
|
|
||||||
|
const combineConditions = this.getNodeParameter('combineConditions', itemIndex) as string;
|
||||||
|
|
||||||
|
for (const dataType of dataTypes) {
|
||||||
|
const typeConditions = this.getNodeParameter(
|
||||||
|
`conditions.${dataType}`,
|
||||||
|
itemIndex,
|
||||||
|
[],
|
||||||
|
) as INodeParameters[];
|
||||||
|
|
||||||
|
for (const condition of typeConditions) {
|
||||||
|
let value1 = condition.value1 as NodeParameterValue;
|
||||||
|
let value2 = condition.value2 as NodeParameterValue;
|
||||||
|
|
||||||
|
if (dataType === 'dateTime') {
|
||||||
|
const node = this.getNode();
|
||||||
|
value1 = convertDateTime(node, value1);
|
||||||
|
value2 = convertDateTime(node, value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const compareResult = compareOperationFunctions[condition.operation as string](
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
);
|
||||||
|
|
||||||
|
// If the operation is "OR" it means the item did match one condition no ned to check further
|
||||||
|
if (compareResult && combineConditions === 'OR') {
|
||||||
|
returnData.push(item);
|
||||||
|
continue itemLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the operation is "AND" it means the item failed one condition no ned to check further
|
||||||
|
if (!compareResult && combineConditions === 'AND') {
|
||||||
|
continue itemLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the operation is "AND" it means the item did match all conditions
|
||||||
|
if (combineConditions === 'AND') returnData.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [returnData];
|
||||||
|
}
|
||||||
|
}
|
101
packages/nodes-base/nodes/Filter/GenericFunctions.ts
Normal file
101
packages/nodes-base/nodes/Filter/GenericFunctions.ts
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import type { INode, NodeParameterValue } from 'n8n-workflow';
|
||||||
|
import { NodeOperationError } from 'n8n-workflow';
|
||||||
|
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
const isDateObject = (value: NodeParameterValue) =>
|
||||||
|
Object.prototype.toString.call(value) === '[object Date]';
|
||||||
|
|
||||||
|
const isDateInvalid = (value: NodeParameterValue) => value?.toString() === 'Invalid Date';
|
||||||
|
|
||||||
|
export const compareOperationFunctions: {
|
||||||
|
[key: string]: (value1: NodeParameterValue, value2: NodeParameterValue) => boolean;
|
||||||
|
} = {
|
||||||
|
after: (value1: NodeParameterValue, value2: NodeParameterValue) => (value1 || 0) > (value2 || 0),
|
||||||
|
before: (value1: NodeParameterValue, value2: NodeParameterValue) => (value1 || 0) < (value2 || 0),
|
||||||
|
contains: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
(value1 || '').toString().includes((value2 || '').toString()),
|
||||||
|
notContains: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
!(value1 || '').toString().includes((value2 || '').toString()),
|
||||||
|
endsWith: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
(value1 as string).endsWith(value2 as string),
|
||||||
|
notEndsWith: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
!(value1 as string).endsWith(value2 as string),
|
||||||
|
equal: (value1: NodeParameterValue, value2: NodeParameterValue) => value1 === value2,
|
||||||
|
notEqual: (value1: NodeParameterValue, value2: NodeParameterValue) => value1 !== value2,
|
||||||
|
larger: (value1: NodeParameterValue, value2: NodeParameterValue) => (value1 || 0) > (value2 || 0),
|
||||||
|
largerEqual: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
(value1 || 0) >= (value2 || 0),
|
||||||
|
smaller: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
(value1 || 0) < (value2 || 0),
|
||||||
|
smallerEqual: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
(value1 || 0) <= (value2 || 0),
|
||||||
|
startsWith: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
(value1 as string).startsWith(value2 as string),
|
||||||
|
notStartsWith: (value1: NodeParameterValue, value2: NodeParameterValue) =>
|
||||||
|
!(value1 as string).startsWith(value2 as string),
|
||||||
|
isEmpty: (value1: NodeParameterValue) =>
|
||||||
|
[undefined, null, '', NaN].includes(value1 as string) ||
|
||||||
|
(typeof value1 === 'object' && value1 !== null && !isDateObject(value1)
|
||||||
|
? Object.entries(value1 as string).length === 0
|
||||||
|
: false) ||
|
||||||
|
(isDateObject(value1) && isDateInvalid(value1)),
|
||||||
|
isNotEmpty: (value1: NodeParameterValue) =>
|
||||||
|
!(
|
||||||
|
[undefined, null, '', NaN].includes(value1 as string) ||
|
||||||
|
(typeof value1 === 'object' && value1 !== null && !isDateObject(value1)
|
||||||
|
? Object.entries(value1 as string).length === 0
|
||||||
|
: false) ||
|
||||||
|
(isDateObject(value1) && isDateInvalid(value1))
|
||||||
|
),
|
||||||
|
regex: (value1: NodeParameterValue, value2: NodeParameterValue) => {
|
||||||
|
const regexMatch = (value2 || '').toString().match(new RegExp('^/(.*?)/([gimusy]*)$'));
|
||||||
|
|
||||||
|
let regex: RegExp;
|
||||||
|
if (!regexMatch) {
|
||||||
|
regex = new RegExp((value2 || '').toString());
|
||||||
|
} else if (regexMatch.length === 1) {
|
||||||
|
regex = new RegExp(regexMatch[1]);
|
||||||
|
} else {
|
||||||
|
regex = new RegExp(regexMatch[1], regexMatch[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!(value1 || '').toString().match(regex);
|
||||||
|
},
|
||||||
|
notRegex: (value1: NodeParameterValue, value2: NodeParameterValue) => {
|
||||||
|
const regexMatch = (value2 || '').toString().match(new RegExp('^/(.*?)/([gimusy]*)$'));
|
||||||
|
|
||||||
|
let regex: RegExp;
|
||||||
|
if (!regexMatch) {
|
||||||
|
regex = new RegExp((value2 || '').toString());
|
||||||
|
} else if (regexMatch.length === 1) {
|
||||||
|
regex = new RegExp(regexMatch[1]);
|
||||||
|
} else {
|
||||||
|
regex = new RegExp(regexMatch[1], regexMatch[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(value1 || '').toString().match(regex);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Converts the input data of a dateTime into a number for easy compare
|
||||||
|
export const convertDateTime = (node: INode, value: NodeParameterValue): number => {
|
||||||
|
let returnValue: number | undefined = undefined;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
returnValue = new Date(value).getTime();
|
||||||
|
} else if (typeof value === 'number') {
|
||||||
|
returnValue = value;
|
||||||
|
}
|
||||||
|
if (moment.isMoment(value)) {
|
||||||
|
returnValue = value.unix();
|
||||||
|
}
|
||||||
|
if ((value as unknown as object) instanceof Date) {
|
||||||
|
returnValue = (value as unknown as Date).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnValue === undefined || isNaN(returnValue)) {
|
||||||
|
throw new NodeOperationError(node, `The value "${value}" is not a valid DateTime.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { testWorkflows, getWorkflowFilenames } from '../../../test/nodes/Helpers';
|
||||||
|
|
||||||
|
const workflows = getWorkflowFilenames(__dirname);
|
||||||
|
|
||||||
|
describe('Test Filter Node', () => testWorkflows(workflows));
|
599
packages/nodes-base/nodes/Filter/test/workflow.json
Normal file
599
packages/nodes-base/nodes/Filter/test/workflow.json
Normal file
|
@ -0,0 +1,599 @@
|
||||||
|
{
|
||||||
|
"name": "filter tests",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"id": "f12d6634-c941-4e1b-837d-5c480678dafa",
|
||||||
|
"name": "When clicking \"Execute Workflow\"",
|
||||||
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [300, 1000]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"jsCode": "return [\n {\n id: 1,\n name: 'Adam',\n subscribed: false,\n updatedAt: '2011-10-05T14:48:00.000Z',\n notes: null,\n email: 'adam@mail.com',\n },\n {\n id: 2,\n name: 'Victor',\n subscribed: true,\n updatedAt: '2020-10-05T14:48:00.000Z',\n notes: 'some notes',\n email: 'victor@mail.com',\n },\n {\n id: 3,\n name: 'Sam',\n subscribed: true,\n updatedAt: '2021-10-05T14:48:00.000Z',\n notes: 'other notes',\n email: 'sam@mail.com',\n }, \n];"
|
||||||
|
},
|
||||||
|
"id": "032d6d92-27f4-4b07-b45f-5b79bdea594a",
|
||||||
|
"name": "Code",
|
||||||
|
"type": "n8n-nodes-base.code",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [600, 1000]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"boolean": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.subscribed }}",
|
||||||
|
"value2": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ !$json.notes }}",
|
||||||
|
"operation": "notEqual",
|
||||||
|
"value2": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "b6935975-5ba9-4daf-b240-7883d34e3198",
|
||||||
|
"name": "Filter Boolean",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 340]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"dateTime": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.updatedAt }}",
|
||||||
|
"value2": "2018-12-31T22:00:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.updatedAt }}",
|
||||||
|
"operation": "before",
|
||||||
|
"value2": "2021-08-03T03:30:08.000Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "56f5f03c-2d65-4abe-bbed-0a14cc2bd7c4",
|
||||||
|
"name": "Filter Date",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 520]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"number": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "smallerEqual",
|
||||||
|
"value2": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"value2": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "notEqual",
|
||||||
|
"value2": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "larger",
|
||||||
|
"value2": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "largerEqual",
|
||||||
|
"value2": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "isNotEmpty"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "equal",
|
||||||
|
"value2": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "b944927d-070b-4e04-9dc2-1e884e7535ae",
|
||||||
|
"name": "Filter Number",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 680]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.notes }}",
|
||||||
|
"operation": "contains",
|
||||||
|
"value2": "notes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "endsWith",
|
||||||
|
"value2": "com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notContains",
|
||||||
|
"value2": "foo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notEndsWith",
|
||||||
|
"value2": "gmail"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.notes }}",
|
||||||
|
"operation": "notContains",
|
||||||
|
"value2": "spam"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notEqual",
|
||||||
|
"value2": "={{ null }}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.name }}",
|
||||||
|
"operation": "regex",
|
||||||
|
"value2": "/^[A-Z][a-z]*$/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.name }}",
|
||||||
|
"operation": "notRegex",
|
||||||
|
"value2": "^[A-Z]+$/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notStartsWith",
|
||||||
|
"value2": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "isNotEmpty"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "19968f30-116e-441a-8cd7-ea9b55deac27",
|
||||||
|
"name": "Filter String",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 820]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"boolean": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.subscribed }}",
|
||||||
|
"value2": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ !$json.notes }}",
|
||||||
|
"operation": "notEqual",
|
||||||
|
"value2": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.subscribed }}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"combineConditions": "OR"
|
||||||
|
},
|
||||||
|
"id": "eebb6476-8f80-4d63-ac37-7c7e4b04c2f0",
|
||||||
|
"name": "Filter Boolean1",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 1020]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"dateTime": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.updatedAt }}",
|
||||||
|
"value2": "2018-12-31T22:00:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.updatedAt }}",
|
||||||
|
"operation": "before",
|
||||||
|
"value2": "2021-08-03T03:30:08.000Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"combineConditions": "OR"
|
||||||
|
},
|
||||||
|
"id": "bd6d0ad9-aede-40d5-96b2-3f8ba96e92ab",
|
||||||
|
"name": "Filter Date1",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 1200]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"number": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "smallerEqual",
|
||||||
|
"value2": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"value2": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "notEqual",
|
||||||
|
"value2": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "larger",
|
||||||
|
"value2": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "largerEqual",
|
||||||
|
"value2": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "isNotEmpty"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.id }}",
|
||||||
|
"operation": "equal",
|
||||||
|
"value2": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"combineConditions": "OR"
|
||||||
|
},
|
||||||
|
"id": "7c93501e-92c1-4b51-823e-3265f9141f3a",
|
||||||
|
"name": "Filter Number1",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 1360]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.notes }}",
|
||||||
|
"operation": "contains",
|
||||||
|
"value2": "notes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "endsWith",
|
||||||
|
"value2": "com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notContains",
|
||||||
|
"value2": "foo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notEndsWith",
|
||||||
|
"value2": "gmail"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.notes }}",
|
||||||
|
"operation": "notContains",
|
||||||
|
"value2": "spam"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notEqual",
|
||||||
|
"value2": "={{ null }}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.name }}",
|
||||||
|
"operation": "regex",
|
||||||
|
"value2": "/^[A-Z][a-z]*$/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.name }}",
|
||||||
|
"operation": "notRegex",
|
||||||
|
"value2": "^[A-Z]+$/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "notStartsWith",
|
||||||
|
"value2": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{ $json.email }}",
|
||||||
|
"operation": "isNotEmpty"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"combineConditions": "OR"
|
||||||
|
},
|
||||||
|
"id": "ba84910a-d2c2-4cc6-b0db-9eec2b54da6c",
|
||||||
|
"name": "Filter String1",
|
||||||
|
"type": "n8n-nodes-base.filter",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1040, 1500]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pinData": {
|
||||||
|
"Filter Boolean": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Victor",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2020-10-05T14:48:00.000Z",
|
||||||
|
"notes": "some notes",
|
||||||
|
"email": "victor@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Sam",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2021-10-05T14:48:00.000Z",
|
||||||
|
"notes": "other notes",
|
||||||
|
"email": "sam@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Filter Date": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Victor",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2020-10-05T14:48:00.000Z",
|
||||||
|
"notes": "some notes",
|
||||||
|
"email": "victor@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Filter Number": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Sam",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2021-10-05T14:48:00.000Z",
|
||||||
|
"notes": "other notes",
|
||||||
|
"email": "sam@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Filter String": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Victor",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2020-10-05T14:48:00.000Z",
|
||||||
|
"notes": "some notes",
|
||||||
|
"email": "victor@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Sam",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2021-10-05T14:48:00.000Z",
|
||||||
|
"notes": "other notes",
|
||||||
|
"email": "sam@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Filter Boolean1": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Adam",
|
||||||
|
"subscribed": false,
|
||||||
|
"updatedAt": "2011-10-05T14:48:00.000Z",
|
||||||
|
"notes": null,
|
||||||
|
"email": "adam@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Victor",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2020-10-05T14:48:00.000Z",
|
||||||
|
"notes": "some notes",
|
||||||
|
"email": "victor@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Sam",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2021-10-05T14:48:00.000Z",
|
||||||
|
"notes": "other notes",
|
||||||
|
"email": "sam@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Filter Date1": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Adam",
|
||||||
|
"subscribed": false,
|
||||||
|
"updatedAt": "2011-10-05T14:48:00.000Z",
|
||||||
|
"notes": null,
|
||||||
|
"email": "adam@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Victor",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2020-10-05T14:48:00.000Z",
|
||||||
|
"notes": "some notes",
|
||||||
|
"email": "victor@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Sam",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2021-10-05T14:48:00.000Z",
|
||||||
|
"notes": "other notes",
|
||||||
|
"email": "sam@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Filter Number1": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Adam",
|
||||||
|
"subscribed": false,
|
||||||
|
"updatedAt": "2011-10-05T14:48:00.000Z",
|
||||||
|
"notes": null,
|
||||||
|
"email": "adam@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Victor",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2020-10-05T14:48:00.000Z",
|
||||||
|
"notes": "some notes",
|
||||||
|
"email": "victor@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Sam",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2021-10-05T14:48:00.000Z",
|
||||||
|
"notes": "other notes",
|
||||||
|
"email": "sam@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Filter String1": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Adam",
|
||||||
|
"subscribed": false,
|
||||||
|
"updatedAt": "2011-10-05T14:48:00.000Z",
|
||||||
|
"notes": null,
|
||||||
|
"email": "adam@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Victor",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2020-10-05T14:48:00.000Z",
|
||||||
|
"notes": "some notes",
|
||||||
|
"email": "victor@mail.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Sam",
|
||||||
|
"subscribed": true,
|
||||||
|
"updatedAt": "2021-10-05T14:48:00.000Z",
|
||||||
|
"notes": "other notes",
|
||||||
|
"email": "sam@mail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"connections": {
|
||||||
|
"When clicking \"Execute Workflow\"": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "Code",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Code": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "Filter Boolean",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Filter Date",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Filter Number",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Filter String",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Filter Boolean1",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Filter Date1",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Filter Number1",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Filter String1",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": false,
|
||||||
|
"settings": {},
|
||||||
|
"versionId": "a4e0701c-9bfd-40aa-b9ec-fc57948d2c0f",
|
||||||
|
"id": "136",
|
||||||
|
"meta": {
|
||||||
|
"instanceId": "36203ea1ce3cef713fa25999bd9874ae26b9e4c2c3a90a365f2882a154d031d0"
|
||||||
|
},
|
||||||
|
"tags": []
|
||||||
|
}
|
|
@ -445,6 +445,7 @@
|
||||||
"dist/nodes/Facebook/FacebookTrigger.node.js",
|
"dist/nodes/Facebook/FacebookTrigger.node.js",
|
||||||
"dist/nodes/Figma/FigmaTrigger.node.js",
|
"dist/nodes/Figma/FigmaTrigger.node.js",
|
||||||
"dist/nodes/FileMaker/FileMaker.node.js",
|
"dist/nodes/FileMaker/FileMaker.node.js",
|
||||||
|
"dist/nodes/Filter/Filter.node.js",
|
||||||
"dist/nodes/Flow/Flow.node.js",
|
"dist/nodes/Flow/Flow.node.js",
|
||||||
"dist/nodes/Flow/FlowTrigger.node.js",
|
"dist/nodes/Flow/FlowTrigger.node.js",
|
||||||
"dist/nodes/FormIo/FormIoTrigger.node.js",
|
"dist/nodes/FormIo/FormIoTrigger.node.js",
|
||||||
|
|
Loading…
Reference in a new issue