[[painless-watcher-transform-context]]
=== Watcher transform context

Use a Painless script as a {ref}/transform-script.html[watch transform]
to transform a payload into a new payload for further use in the watch.
Transform scripts return an Object value of the new payload.

include::painless-watcher-context-variables.asciidoc[]

*Return*

`Object`::
        The new payload.

*API*

The standard <<painless-api-reference, Painless API>> is available.

*Example*

[source,console]
----
POST _watcher/watch/_execute
{
  "watch" : {
    "trigger" : { "schedule" : { "interval" : "24h" } },
    "input" : {
      "search" : {
        "request" : {
          "indices" : [ "seats" ],
          "body" : {
            "query" : { "term": { "sold": "true"} },
            "aggs" : {
              "theatres" : {
                "terms" : { "field" : "play" },
                "aggs" : {
                  "money" : {
                    "sum": { "field" : "cost" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "transform" : {
      "script":
      """
        return [
          'money_makers': ctx.payload.aggregations.theatres.buckets.stream()  <1>
            .filter(t -> {                                                    <2>
                return t.money.value > 50000
            })
            .map(t -> {                                                       <3>
                return ['play': t.key, 'total_value': t.money.value ]
            }).collect(Collectors.toList()),                                  <4>
          'duds' : ctx.payload.aggregations.theatres.buckets.stream()         <5>
            .filter(t -> {
                return t.money.value < 15000
            })
            .map(t -> {
                return ['play': t.key, 'total_value': t.money.value ]
            }).collect(Collectors.toList())
          ]
      """
    },
    "actions" : {
      "my_log" : {
        "logging" : {
          "text" : "The output of the payload was transformed to {{ctx.payload}}"
        }
      }
    }
  }
}
----
// TEST[skip: requires setup from other pages]

<1> The Java Stream API is used in the transform. This API allows manipulation of
the elements of the list in a pipeline.
<2> The stream filter removes items that do not meet the filter criteria.
<3> The stream map transforms each element into a new object.
<4> The collector reduces the stream to a `java.util.List`.
<5> This is done again for the second set of values in the transform.

The following action transform changes each value in the mod_log action into a `String`.
This transform does not change the values in the unmod_log action.

[source,console]
----
POST _watcher/watch/_execute
{
  "watch" : {
    "trigger" : { "schedule" : { "interval" : "24h" } },
    "input" : {
      "search" : {
        "request" : {
          "indices" : [ "seats" ],
          "body" : {
            "query" : {
              "term": { "sold": "true"}
            },
            "aggs" : {
              "theatres" : {
                "terms" : { "field" : "play" },
                "aggs" : {
                  "money" : {
                    "sum": { "field" : "cost" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "actions" : {
      "mod_log" : {
        "transform": {                                                                <1>
          "script" :
          """
          def formatter = NumberFormat.getCurrencyInstance();
          return [
            'msg': ctx.payload.aggregations.theatres.buckets.stream()
              .map(t-> formatter.format(t.money.value) + ' for the play ' + t.key)
              .collect(Collectors.joining(", "))
          ]
          """
        },
        "logging" : {
          "text" : "The output of the payload was transformed to: {{ctx.payload.msg}}"
        }
      },
      "unmod_log" : {                                                                 <2>
        "logging" : {
          "text" : "The output of the payload was not transformed and this value should not exist: {{ctx.payload.msg}}"
        }
      }
    }
  }
}
----
// TEST[skip: requires setup from other pages]

This example uses the streaming API in a very similar manner. The differences below are
subtle and worth calling out.

<1> The location of the transform is no longer at the top level, but is within
an individual action.
<2> A second action that does not transform the payload is given for reference.

The following example shows scripted watch and action transforms within the
context of a complete watch. This watch also uses a scripted
<<painless-watcher-condition-context, condition>>.

include::painless-watcher-context-example.asciidoc[]
