diff --git a/docs/code-examples/expressions/jmespath.md b/docs/code-examples/expressions/jmespath.md index 363eb1fc2..b6437e87c 100644 --- a/docs/code-examples/expressions/jmespath.md +++ b/docs/code-examples/expressions/jmespath.md @@ -31,7 +31,7 @@ jmespath.search(object, searchString); ## Common tasks -This section provides examples for some common operations. Many more examples, and detailed guidance, are available in [JMESPath's own documentation](https://jmespath.org/tutorial.html). +This section provides examples for some common operations. More examples, and detailed guidance, are available in [JMESPath's own documentation](https://jmespath.org/tutorial.html). ### A shorter way to write basic operations diff --git a/docs/code-examples/expressions/luxon.md b/docs/code-examples/expressions/luxon.md index 63c25705b..59310105f 100644 --- a/docs/code-examples/expressions/luxon.md +++ b/docs/code-examples/expressions/luxon.md @@ -11,7 +11,6 @@ n8n uses Luxon to provide two custom variables: Note that these variables can return different time formats when cast as a string. This is the same behavior as Luxon's `DateTime.now()`. - ``` js {{$now}} // Returns [Object: ""] @@ -24,6 +23,15 @@ Note that these variables can return different time formats when cast as a strin // For example "Today's date is 1646834498755" ``` +When performing operations in expressions using these variables, they return an object. Use `toISO()` to get just the date and time. For example: + +```js +{{$today.minus({days: 7})}} +// On 9th May 2022, this returns [Object: "2022-05-02T00:00:00.000+01:00"] +{{$today.minus({days: 7}).toISO()}} +// On 9th May 2022, this returns 2022-05-02T00:00:00.000+01:00 +``` + ## Setting the timezone in n8n Luxon uses the n8n timezone. This value is either: @@ -34,7 +42,7 @@ Luxon uses the n8n timezone. This value is either: ## Common tasks -This section provides examples for some common operations. Many more examples, and detailed guidance, are available in [Luxon's own documentation](https://moment.github.io/luxon/#/?id=luxon). +This section provides examples for some common operations. More examples, and detailed guidance, are available in [Luxon's own documentation](https://moment.github.io/luxon/#/?id=luxon). ### Get n days from today @@ -51,7 +59,7 @@ In the expressions editor, enter: On the 23rd June 2019, this returns `[Object: "2019-06-16T00:00:00.000+00:00"]`. -This example uses n8n's custom variable `$today` for convenience. It is the equivalent of `DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).minus({days: 7})`. +This example uses n8n's custom variable `$today` for convenience. It's the equivalent of `DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).minus({days: 7})`. For more detailed information and examples, refer to: @@ -89,7 +97,7 @@ If you have a date in a supported standard technical format: Luxon provides functions to handle the conversion. Refer to Luxon's guide to [Parsing technical formats](https://moment.github.io/luxon/#/parsing?id=parsing-technical-formats) for details. -If you have a date as a string that does not use a standard format: +If you have a date as a string that doesn't use a standard format: Use Luxon's [Ad-hoc parsing](https://moment.github.io/luxon/#/parsing?id=ad-hoc-parsing). To do this, use the `fromFormat()` function, providing the string and a set of [tokens](https://moment.github.io/luxon/#/parsing?id=table-of-tokens) that describe the format. @@ -109,14 +117,14 @@ To get the time between two dates, use Luxon's diffs feature. This subtracts one For example, get the number of months between two dates: ```js -{{DateTime.fromISO('201-06-23').diff(DateTime.fromISO('2019-05-23'), 'months').toObject()}} +{{DateTime.fromISO('2019-06-23').diff(DateTime.fromISO('2019-05-23'), 'months').toObject()}} ``` This returns `[Object: {"months":1}]`. Refer to Luxon's [Diffs](https://moment.github.io/luxon/#/math?id=diffs) for more information. -### A longer example: how many days to Christmas? +### A longer example: How many days to Christmas? This example brings together several Luxon features, uses JMESPath, and does some basic string manipulation. diff --git a/docs/code-examples/javascript-functions/jmespath.md b/docs/code-examples/javascript-functions/jmespath.md new file mode 100644 index 000000000..becd6aa33 --- /dev/null +++ b/docs/code-examples/javascript-functions/jmespath.md @@ -0,0 +1,279 @@ +# Query JSON with JMESPath + +[JMESPath](https://jmespath.org/) is a query language for JSON, allowing you to extract and transform elements from a JSON document. For full details of how to use JMESPath, refer to the [JMESPath documentation](https://jmespath.org/tutorial.html). + +## The `$jmespath()` method + +n8n provides a custom method, `$jmespath()`. It allows you to perform a search on a JSON object using the JMESPath query language. + +The basic syntax is: + + +```js +$jmespath(object, searchString) +``` + + +To help understand what the method does, here is the equivalent longer JavaScript: + + +```js +var jmespath = require('jmespath'); +jmespath.search(object, searchString); +``` + + +`object` is a JSON object, such as the output of a previous node. `searchString` is an expression written in the JMESPath query language. The [JMESPath Specification](https://jmespath.org/specification.html#jmespath-specification) provides a list of supported expressions, while their [Tutorial](https://jmespath.org/tutorial.html) and [Examples](https://jmespath.org/examples.html) provide interactive examples. + +!!! warning "Search parameter order" + The examples in the [JMESPath Specification](https://jmespath.org/specification.html#jmespath-specification) follow the pattern `search(searchString, object)`. The [JMESPath JavaScript library](https://github.com/jmespath/jmespath.js/), which n8n uses, supports `search(object, searchString)` instead. This means that when using examples from the JMESPath documentation, you may need to change the order of the search function parameters. + +!!! note "Array or object" + + + +## Common tasks + +This section provides examples for some common operations. More examples, and detailed guidance, are available in [JMESPath's own documentation](https://jmespath.org/tutorial.html). + +### A shorter way to write basic operations + +JMESPath provides a shorter and more readable way to write basic JSON queries. + +Consider the following scenario: you have a webhook trigger that receives data through the webhook body. You want to extract some of that data for use in the workflow. + +Your webhook data looks similar to this: + + +```json +[ + { + "headers": { + "host": "n8n.instance.address", + ... + }, + "params": {}, + "query": {}, + "body": { + "name": "Jim", + "age": 30, + "city": "New York", + "dogs": ["Fido", "Spot"] + } + } +] +``` + + +Extract the city: + + +```js +// With JMESPath +$json.body.city +// Without JMESPath +$json['body']['city'] +``` + + + +Get the first dog in `dogs[]`: + + +```js +// With JMESPath +$json.body.dogs[0] +// Without JMESPath +$json['body']['dogs'][0] +``` + +### Apply a JMESPath expression to a collection of elements with projections + +From the [JMESPath projections documentation](https://jmespath.org/tutorial.html#projections): + +> Projections are one of the key features of JMESPath. It allows you to apply an expression to a collection of elements. JMESPath supports five kinds of projections: +> +> * List Projections +> * Slice Projections +> * Object Projections +> * Flatten Projections +> * Filter Projections + +The following example shows basic usage of list, slice, and object projections. Refer to the [JMESPath projections documentation](https://jmespath.org/tutorial.html#projections) for detailed explanations of each projection type, and more examples. + +Given this JSON from a webhook node: + + +```js +[ + { + "headers": { + "host": "n8n.instance.address", + ... + }, + "params": {}, + "query": {}, + "body": { + "people": [ + { + "first": "James", + "last": "Green" + }, + { + "first": "Jacob", + "last": "Jones" + }, + { + "first": "Jayden", + "last": "Smith" + } + ], + "dogs": { + "Fido": { + "color": "brown", + "age": 7 + }, + "Spot": { + "color": "black and white", + "age": 5 + } + } + } + } +] + +``` + + +Retrieve a [list](https://jmespath.org/tutorial.html#list-and-slice-projections) of all the people's first names: + + +```js +$jmespath($json.body.people, "[*].first" ) +/* Returns: +[ + { + "firstNames": [ + "James", + "Jacob", + "Jayden" + ] + } +] +*/ +``` + + +Get a [slice](https://jmespath.org/tutorial.html#list-and-slice-projections) of the first names: + + +```js +$jmespath($json.body.people, "[:2].first") +/* Returns: +[ + { + "firstNames": [ + "James", + "Jacob", + "Jayden" + ] + } +] +*/ +``` + +Get a list of the dogs' ages using [object projections](https://jmespath.org/tutorial.html#object-projections): + + +```js +$jmespath($json.body.dogs, "*.age") +/* Returns: +[ + { + "firstNames": [ + "James", + "Jacob", + "Jayden" + ] + } +] +*/ +``` + + +### Select multiple elements and create a new list or object + +[Multiselect](https://jmespath.org/tutorial.html#multiselect) allows you to select elements from a JSON object and combine them into a new list or object. + +Given this JSON from a webhook node: + + +```js +[ + { + "headers": { + "host": "n8n.instance.address", + ... + }, + "params": {}, + "query": {}, + "body": { + "people": [ + { + "first": "James", + "last": "Green" + }, + { + "first": "Jacob", + "last": "Jones" + }, + { + "first": "Jayden", + "last": "Smith" + } + ], + "dogs": { + "Fido": { + "color": "brown", + "age": 7 + }, + "Spot": { + "color": "black and white", + "age": 5 + } + } + } + } +] + +``` + + +Use multiselect list to get the first and last names and create new lists containing both names: + + +```js +$jmespath($json.body.people, "[].[first, last]") +/* Returns: +[ + { + "fullNames": [ + [ + "James", + "Green" + ], + [ + "Jacob", + "Jones" + ], + [ + "Jayden", + "Smith" + ] + ] + } +] +*/ +``` + + diff --git a/docs/code-examples/javascript-functions/luxon.md b/docs/code-examples/javascript-functions/luxon.md new file mode 100644 index 000000000..8e078746c --- /dev/null +++ b/docs/code-examples/javascript-functions/luxon.md @@ -0,0 +1,142 @@ +# Date and time with Luxon + +[Luxon](https://github.com/moment/luxon/) is a JavaScript library that makes it easier to work with date and time. For full details of how to use Luxon, refer to [Luxon's documentation](https://moment.github.io/luxon/#/?id=luxon). + +## Variables + +n8n uses Luxon to provide two custom variables: + +- `$now`: a Luxon object containing the current timestamp. Equivalent to `DateTime.now()`. +- `$today`: a Luxon object containing the current timestamp, rounded down to the day. Equivalent to `DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 })`. + +Note that these variables can return different time formats when cast as a string. This is the same behavior as Luxon's `DateTime.now()`. + + +``` js +$now +// Returns +// For example 2022-03-09T14:00:25.058+00:00 +"Today's date is " + $now +// Returns "Today's date is " +// For example "Today's date is 1646834498755" +``` + +## Setting the timezone in n8n + +Luxon uses the n8n timezone. This value is either: + +* Default: `America/New York` +* A custom timezone for your n8n instance, set using the `GENERIC_TIMEZONE` environment variable. +* A custome timezone for an individual workflow, configured in workflow settings. + +## Common tasks + +This section provides examples for some common operations. More examples, and detailed guidance, are available in [Luxon's own documentation](https://moment.github.io/luxon/#/?id=luxon). + +### Get n days from today + +Get a number of days before or after today. + +For example, you want a variable containing the date seven days before the current date. + +In the code editor, enter: + +``` js +let sevenDaysAgo = $today.minus({days: 7}) +``` + +On the 23rd June 2019, this returns `[Object: "2019-06-16T00:00:00.000+00:00"]`. + +This example uses n8n's custom variable `$today` for convenience. It's the equivalent of `DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).minus({days: 7})`. + + +For more detailed information and examples, refer to: + +* Luxon's [guide to math](https://moment.github.io/luxon/#/math) +* Their API documentation on [DateTime plus](https://moment.github.io/luxon/api-docs/index.html#datetimeplus) and [DateTime minus](https://moment.github.io/luxon/api-docs/index.html#datetimeminus) + +### Create human-readable dates + +In [Get n days from today](#get-n-days-from-today), the example gets the date seven days before the current date, and returns it as `yyyy-mm-dd-T00:00:00.000+00:00`. To make this more readable, you can use Luxon's formatting functions. + +For example, you want the field containing the date to be formatted as DD/MM/YYYY, so that on the 23rd June 2019, it returns 23/06/2019 + +This expression gets the date seven days before today, and converts it to the DD/MM/YYYY format. + +```js +let readableSevenDaysAgo = $today.minus({days: 7}).toLocaleString() +``` + +You can alter the format. For example: + +```js +let readableSevenDaysAgo = $today.minus({days: 7}).toLocaleString({month: 'long', day: 'numeric', year: 'numeric'}) +``` + +On 23rd June 2019, this returns "16 June 2019". + +Refer to Luxon's guide on [toLocaleString (strings for humans)](https://moment.github.io/luxon/#/formatting?id=tolocalestring-strings-for-humans) for more information. + +### Convert date string to Luxon + +You can convert date strings and other date formats to a Luxon DateTime object. You can convert from standard formats and from arbitrary strings. + +If you have a date in a supported standard technical format: + +Luxon provides functions to handle the conversion. Refer to Luxon's guide to [Parsing technical formats](https://moment.github.io/luxon/#/parsing?id=parsing-technical-formats) for details. + +If you have a date as a string that doesn't use a standard format: + +Use Luxon's [Ad-hoc parsing](https://moment.github.io/luxon/#/parsing?id=ad-hoc-parsing). To do this, use the `fromFormat()` function, providing the string and a set of [tokens](https://moment.github.io/luxon/#/parsing?id=table-of-tokens) that describe the format. + +For example, you have n8n's founding date, 23rd June 2019, formatted as '23-06-2019'. You want to turn this into a Luxon object: + +```js +let newFormat = DateTime.fromFormat("23-06-2019", "dd-MM-yyyy") +``` + +When using ad-hoc parsing, note Luxon's warning about [Limitations](https://moment.github.io/luxon/#/parsing?id=limitations). If you see unexpected results, try their [Debugging](https://moment.github.io/luxon/#/parsing?id=debugging) guide. + + +### Get the time between two dates + +To get the time between two dates, use Luxon's diffs feature. This subtracts one date from another and returns a duration. + +For example, get the number of months between two dates: + +```js +let monthsBetweenDates = DateTime.fromISO('2019-06-23').diff(DateTime.fromISO('2019-05-23'), 'months').toObject() +``` + +This returns `{"months":1}`. + +Refer to Luxon's [Diffs](https://moment.github.io/luxon/#/math?id=diffs) for more information. + +### A longer example: How many days to Christmas? + +This example brings together several Luxon features, uses JMESPath, and does some basic string manipulation. + +The scenario: you want a countdown to 25th December. Every day, it should tell you the number of days remaining to Christmas. You don't want to update it for next year - it needs to seamelessly work for every year. + +```js +let daysToChristmas = "There are " + $today.diff(DateTime.fromISO($today.year + '-12-25'), 'days').toObject().days.toString().substring(1) + " days to Christmas!"; +``` + +This outputs `"There are days to Christmas!"`. For example, on 9th March, it outputs "There are 291 days to Christmas!". + +A detailed explanation of what the code does: + +* `"There are "`: a string. +* `+`: used to join two strings. +* `$today.diff()`: This is similar to the example in [Get the time between two dates](#get-the-time-between-two-dates), but it uses n8n's custom `$today` variable. +* `DateTime.fromISO($today.year + '-12-25'), 'days'`: this part gets the current year using `$today.year`, turns it into an ISO string along with the month and date, and then takes the whole ISO string and converts it to a Luxon DateTime data structure. It also tells Luxon that you want the duration in days. +* `toObject()` turns the result of diff() into a more usable object. At this point, the expression returns `[Object: {"days":-}]`. For example, on 9th March, `[Object: {"days":-291}]`. +* `.days` uses JMESPath syntax to retrieve just the number of days from the object. For more information on using JMESPath with n8n, refer to our [JMESpath](/code-examples/javascript-functions/jmespath/) documentation. This gives you the number of days to Christmas, as a negative number. +* `.toString().substring(1)` turns the number into a string and removes the `-`. +* `+ " days to Christmas!"`: another string, with a `+` to join it to the previous string. + + + + + + diff --git a/docs/code-examples/javascript-functions/split-binary-file-data.md b/docs/code-examples/javascript-functions/split-binary-file-data.md new file mode 100644 index 000000000..39181eb6a --- /dev/null +++ b/docs/code-examples/javascript-functions/split-binary-file-data.md @@ -0,0 +1,22 @@ +# Split binary file data into individual items + +If you receive more than one binary file from a node, you can split the binary data into individual items using the following code snippet. + +```js +let results = []; + +for (item of items) { + for (key of Object.keys(item.binary)) { + results.push({ + json: { + fileName: item.binary[key].fileName + }, + binary: { + data: item.binary[key], + } + }); + } +} + +return results; +``` \ No newline at end of file diff --git a/docs/integrations/core-nodes/n8n-nodes-base.function.md b/docs/integrations/core-nodes/n8n-nodes-base.function.md index 55fa67865..d7d01e230 100644 --- a/docs/integrations/core-nodes/n8n-nodes-base.function.md +++ b/docs/integrations/core-nodes/n8n-nodes-base.function.md @@ -46,7 +46,7 @@ In n8n, all data passed between nodes is an array of objects. It has the followi ``` !!! note "Skipping the 'json' key and array syntax" - From 0.166.0 onwards, n8n automatically adds the `json` key if it is missing. It also automatically wraps your items in an array (`[]`) if needed. + From 0.166.0 onwards, n8n automatically adds the `json` key if it's missing. It also automatically wraps your items in an array (`[]`) if needed. This is only when using the Function node. When building your own nodes, you must still make sure the node returns data with the `json` key. diff --git a/mkdocs.yml b/mkdocs.yml index 160ecc1dc..25b8f17c5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -94,7 +94,9 @@ nav: - Overview: code-examples/javascript-functions/index.md - Methods: code-examples/javascript-functions/methods.md - Variables: code-examples/javascript-functions/variables.md + - Data and time with Luxon: code-examples/javascript-functions/luxon.md - Get number of items returned by last node: code-examples/javascript-functions/number-items-last-node.md + - Split binary file data into individual items: code-examples/javascript-functions/split-binary-file-data.md - Check incoming data: code-examples/javascript-functions/check-incoming-data.md - Reference: - Overview: reference/index.md