github.com/Jeffail/benthos/v3@v3.65.0/website/docs/guides/bloblang/methods.md (about) 1 --- 2 title: Bloblang Methods 3 sidebar_label: Methods 4 description: A list of Bloblang methods 5 --- 6 7 <!-- 8 THIS FILE IS AUTOGENERATED! 9 10 To make changes please edit the contents of: 11 internal/bloblang/query/methods.go 12 internal/bloblang/query/methods_strings.go 13 internal/docs/bloblang.go 14 --> 15 16 import Tabs from '@theme/Tabs'; 17 import TabItem from '@theme/TabItem'; 18 19 Methods provide most of the power in Bloblang as they allow you to augment values and can be added to any expression (including other methods): 20 21 ```coffee 22 root.doc.id = this.thing.id.string().catch(uuid_v4()) 23 root.doc.reduced_nums = this.thing.nums.map_each(num -> if num < 10 { 24 deleted() 25 } else { 26 num - 10 27 }) 28 root.has_good_taste = ["pikachu","mewtwo","magmar"].contains(this.user.fav_pokemon) 29 ``` 30 31 Methods support both named and nameless style arguments: 32 33 ```coffee 34 root.foo_one = this.(bar | baz).trim().replace(old: "dog", new: "cat") 35 root.foo_two = this.(bar | baz).trim().replace("dog", "cat") 36 ``` 37 38 ## General 39 40 ### `apply` 41 42 Apply a declared mapping to a target value. 43 44 #### Parameters 45 46 **`mapping`** <string> The mapping to apply. 47 48 #### Examples 49 50 51 ```coffee 52 map thing { 53 root.inner = this.first 54 } 55 56 root.foo = this.doc.apply("thing") 57 58 # In: {"doc":{"first":"hello world"}} 59 # Out: {"foo":{"inner":"hello world"}} 60 ``` 61 62 ```coffee 63 map create_foo { 64 root.name = "a foo" 65 root.purpose = "to be a foo" 66 } 67 68 root = this 69 root.foo = null.apply("create_foo") 70 71 # In: {"id":"1234"} 72 # Out: {"foo":{"name":"a foo","purpose":"to be a foo"},"id":"1234"} 73 ``` 74 75 ### `catch` 76 77 If the result of a target query fails (due to incorrect types, failed parsing, etc) the argument is returned instead. 78 79 #### Parameters 80 81 **`fallback`** <query expression> A value to yield, or query to execute, if the target query fails. 82 83 #### Examples 84 85 86 ```coffee 87 root.doc.id = this.thing.id.string().catch(uuid_v4()) 88 ``` 89 90 When the input document is not structured attempting to reference structured fields with `this` will result in an error. Therefore, a convenient way to delete non-structured data is with a catch. 91 92 ```coffee 93 root = this.catch(deleted()) 94 95 # In: {"doc":{"foo":"bar"}} 96 # Out: {"doc":{"foo":"bar"}} 97 98 # In: not structured data 99 # Out: <Message deleted> 100 ``` 101 102 ### `exists` 103 104 Checks that a field, identified via a [dot path][field_paths], exists in an object. 105 106 #### Parameters 107 108 **`path`** <string> A [dot path][field_paths] to a field. 109 110 #### Examples 111 112 113 ```coffee 114 root.result = this.foo.exists("bar.baz") 115 116 # In: {"foo":{"bar":{"baz":"yep, I exist"}}} 117 # Out: {"result":true} 118 119 # In: {"foo":{"bar":{}}} 120 # Out: {"result":false} 121 122 # In: {"foo":{}} 123 # Out: {"result":false} 124 ``` 125 126 ### `from` 127 128 Modifies a target query such that certain functions are executed from the perspective of another message in the batch. This allows you to mutate events based on the contents of other messages. Functions that support this behaviour are `content`, `json` and `meta`. 129 130 #### Parameters 131 132 **`index`** <integer> The message index to use as a perspective. 133 134 #### Examples 135 136 137 For example, the following map extracts the contents of the JSON field `foo` specifically from message index `1` of a batch, effectively overriding the field `foo` for all messages of a batch to that of message 1: 138 139 ```coffee 140 root = this 141 root.foo = json("foo").from(1) 142 ``` 143 144 ### `from_all` 145 146 Modifies a target query such that certain functions are executed from the perspective of each message in the batch, and returns the set of results as an array. Functions that support this behaviour are `content`, `json` and `meta`. 147 148 #### Examples 149 150 151 ```coffee 152 root = this 153 root.foo_summed = json("foo").from_all().sum() 154 ``` 155 156 ### `or` 157 158 If the result of the target query fails or resolves to `null`, returns the argument instead. This is an explicit method alternative to the coalesce pipe operator `|`. 159 160 #### Parameters 161 162 **`fallback`** <query expression> A value to yield, or query to execute, if the target query fails or resolves to `null`. 163 164 #### Examples 165 166 167 ```coffee 168 root.doc.id = this.thing.id.or(uuid_v4()) 169 ``` 170 171 ## String Manipulation 172 173 ### `capitalize` 174 175 Takes a string value and returns a copy with all Unicode letters that begin words mapped to their Unicode title case. 176 177 #### Examples 178 179 180 ```coffee 181 root.title = this.title.capitalize() 182 183 # In: {"title":"the foo bar"} 184 # Out: {"title":"The Foo Bar"} 185 ``` 186 187 ### `contains` 188 189 Checks whether a string contains a substring and returns a boolean result. 190 191 #### Parameters 192 193 **`value`** <unknown> A value to test against elements of the target. 194 195 #### Examples 196 197 198 ```coffee 199 root.has_foo = this.thing.contains("foo") 200 201 # In: {"thing":"this foo that"} 202 # Out: {"has_foo":true} 203 204 # In: {"thing":"this bar that"} 205 # Out: {"has_foo":false} 206 ``` 207 208 ### `escape_html` 209 210 Escapes a string so that special characters like `<` to become `<`. It escapes only five such characters: `<`, `>`, `&`, `'` and `"` so that it can be safely placed within an HTML entity. 211 212 #### Examples 213 214 215 ```coffee 216 root.escaped = this.value.escape_html() 217 218 # In: {"value":"foo & bar"} 219 # Out: {"escaped":"foo & bar"} 220 ``` 221 222 ### `escape_url_query` 223 224 Escapes a string so that it can be safely placed within a URL query. 225 226 #### Examples 227 228 229 ```coffee 230 root.escaped = this.value.escape_url_query() 231 232 # In: {"value":"foo & bar"} 233 # Out: {"escaped":"foo+%26+bar"} 234 ``` 235 236 ### `filepath_join` 237 238 Joins an array of path elements into a single file path. The separator depends on the operating system of the machine. 239 240 #### Examples 241 242 243 ```coffee 244 root.path = this.path_elements.filepath_join() 245 246 # In: {"path_elements":["/foo/","bar.txt"]} 247 # Out: {"path":"/foo/bar.txt"} 248 ``` 249 250 ### `filepath_split` 251 252 Splits a file path immediately following the final Separator, separating it into a directory and file name component returned as a two element array of strings. If there is no Separator in the path, the first element will be empty and the second will contain the path. The separator depends on the operating system of the machine. 253 254 #### Examples 255 256 257 ```coffee 258 root.path_sep = this.path.filepath_split() 259 260 # In: {"path":"/foo/bar.txt"} 261 # Out: {"path_sep":["/foo/","bar.txt"]} 262 263 # In: {"path":"baz.txt"} 264 # Out: {"path_sep":["","baz.txt"]} 265 ``` 266 267 ### `format` 268 269 Use a value string as a format specifier in order to produce a new string, using any number of provided arguments. 270 271 #### Examples 272 273 274 ```coffee 275 root.foo = "%s(%v): %v".format(this.name, this.age, this.fingers) 276 277 # In: {"name":"lance","age":37,"fingers":13} 278 # Out: {"foo":"lance(37): 13"} 279 ``` 280 281 ### `has_prefix` 282 283 Checks whether a string has a prefix argument and returns a bool. 284 285 #### Parameters 286 287 **`value`** <string> The string to test. 288 289 #### Examples 290 291 292 ```coffee 293 root.t1 = this.v1.has_prefix("foo") 294 root.t2 = this.v2.has_prefix("foo") 295 296 # In: {"v1":"foobar","v2":"barfoo"} 297 # Out: {"t1":true,"t2":false} 298 ``` 299 300 ### `has_suffix` 301 302 Checks whether a string has a suffix argument and returns a bool. 303 304 #### Parameters 305 306 **`value`** <string> The string to test. 307 308 #### Examples 309 310 311 ```coffee 312 root.t1 = this.v1.has_suffix("foo") 313 root.t2 = this.v2.has_suffix("foo") 314 315 # In: {"v1":"foobar","v2":"barfoo"} 316 # Out: {"t1":false,"t2":true} 317 ``` 318 319 ### `index_of` 320 321 Returns the starting index of the argument substring in a string target, or `-1` if the target doesn't contain the argument. 322 323 #### Parameters 324 325 **`value`** <string> A string to search for. 326 327 #### Examples 328 329 330 ```coffee 331 root.index = this.thing.index_of("bar") 332 333 # In: {"thing":"foobar"} 334 # Out: {"index":3} 335 ``` 336 337 ```coffee 338 root.index = content().index_of("meow") 339 340 # In: the cat meowed, the dog woofed 341 # Out: {"index":8} 342 ``` 343 344 ### `length` 345 346 Returns the length of a string. 347 348 #### Examples 349 350 351 ```coffee 352 root.foo_len = this.foo.length() 353 354 # In: {"foo":"hello world"} 355 # Out: {"foo_len":11} 356 ``` 357 358 ### `lowercase` 359 360 Convert a string value into lowercase. 361 362 #### Examples 363 364 365 ```coffee 366 root.foo = this.foo.lowercase() 367 368 # In: {"foo":"HELLO WORLD"} 369 # Out: {"foo":"hello world"} 370 ``` 371 372 ### `quote` 373 374 Quotes a target string using escape sequences (`\t`, `\n`, `\xFF`, `\u0100`) for control characters and non-printable characters. 375 376 #### Examples 377 378 379 ```coffee 380 root.quoted = this.thing.quote() 381 382 # In: {"thing":"foo\nbar"} 383 # Out: {"quoted":"\"foo\\nbar\""} 384 ``` 385 386 ### `replace` 387 388 Replaces all occurrences of the first argument in a target string with the second argument. 389 390 #### Parameters 391 392 **`old`** <string> A string to match against. 393 **`new`** <string> A string to replace with. 394 395 #### Examples 396 397 398 ```coffee 399 root.new_value = this.value.replace("foo","dog") 400 401 # In: {"value":"The foo ate my homework"} 402 # Out: {"new_value":"The dog ate my homework"} 403 ``` 404 405 ### `replace_many` 406 407 For each pair of strings in an argument array, replaces all occurrences of the first item of the pair with the second. This is a more compact way of chaining a series of `replace` methods. 408 409 #### Parameters 410 411 **`values`** <array> An array of values, each even value will be replaced with the following odd value. 412 413 #### Examples 414 415 416 ```coffee 417 root.new_value = this.value.replace_many([ 418 "<b>", "<b>", 419 "</b>", "</b>", 420 "<i>", "<i>", 421 "</i>", "</i>", 422 ]) 423 424 # In: {"value":"<i>Hello</i> <b>World</b>"} 425 # Out: {"new_value":"<i>Hello</i> <b>World</b>"} 426 ``` 427 428 ### `reverse` 429 430 Returns the target string in reverse order. 431 432 #### Examples 433 434 435 ```coffee 436 root.reversed = this.thing.reverse() 437 438 # In: {"thing":"backwards"} 439 # Out: {"reversed":"sdrawkcab"} 440 ``` 441 442 ```coffee 443 root = content().reverse() 444 445 # In: {"thing":"backwards"} 446 # Out: }"sdrawkcab":"gniht"{ 447 ``` 448 449 ### `slice` 450 451 Extract a slice from a string by specifying two indices, a low and high bound, which selects a half-open range that includes the first character, but excludes the last one. If the second index is omitted then it defaults to the length of the input sequence. 452 453 #### Parameters 454 455 **`low`** <integer> The low bound, which is the first element of the selection, or if negative selects from the end. 456 **`high`** <(optional) integer> An optional high bound. 457 458 #### Examples 459 460 461 ```coffee 462 root.beginning = this.value.slice(0, 2) 463 root.end = this.value.slice(4) 464 465 # In: {"value":"foo bar"} 466 # Out: {"beginning":"fo","end":"bar"} 467 ``` 468 469 A negative low index can be used, indicating an offset from the end of the sequence. If the low index is greater than the length of the sequence then an empty result is returned. 470 471 ```coffee 472 root.last_chunk = this.value.slice(-4) 473 root.the_rest = this.value.slice(0, -4) 474 475 # In: {"value":"foo bar"} 476 # Out: {"last_chunk":" bar","the_rest":"foo"} 477 ``` 478 479 ### `split` 480 481 Split a string value into an array of strings by splitting it on a string separator. 482 483 #### Parameters 484 485 **`delimiter`** <string> The delimiter to split with. 486 487 #### Examples 488 489 490 ```coffee 491 root.new_value = this.value.split(",") 492 493 # In: {"value":"foo,bar,baz"} 494 # Out: {"new_value":["foo","bar","baz"]} 495 ``` 496 497 ### `strip_html` 498 499 Attempts to remove all HTML tags from a target string. 500 501 #### Parameters 502 503 **`preserve`** <(optional) array> An optional array of element types to preserve in the output. 504 505 #### Examples 506 507 508 ```coffee 509 root.stripped = this.value.strip_html() 510 511 # In: {"value":"<p>the plain <strong>old text</strong></p>"} 512 # Out: {"stripped":"the plain old text"} 513 ``` 514 515 It's also possible to provide an explicit list of element types to preserve in the output. 516 517 ```coffee 518 root.stripped = this.value.strip_html(["article"]) 519 520 # In: {"value":"<article><p>the plain <strong>old text</strong></p></article>"} 521 # Out: {"stripped":"<article>the plain old text</article>"} 522 ``` 523 524 ### `trim` 525 526 Remove all leading and trailing characters from a string that are contained within an argument cutset. If no arguments are provided then whitespace is removed. 527 528 #### Parameters 529 530 **`cutset`** <(optional) string> An optional string of characters to trim from the target value. 531 532 #### Examples 533 534 535 ```coffee 536 root.title = this.title.trim("!?") 537 root.description = this.description.trim() 538 539 # In: {"description":" something happened and its amazing! ","title":"!!!watch out!?"} 540 # Out: {"description":"something happened and its amazing!","title":"watch out"} 541 ``` 542 543 ### `unescape_html` 544 545 Unescapes a string so that entities like `<` become `<`. It unescapes a larger range of entities than `escape_html` escapes. For example, `á` unescapes to `á`, as does `á` and `&xE1;`. 546 547 #### Examples 548 549 550 ```coffee 551 root.unescaped = this.value.unescape_html() 552 553 # In: {"value":"foo & bar"} 554 # Out: {"unescaped":"foo & bar"} 555 ``` 556 557 ### `unescape_url_query` 558 559 Expands escape sequences from a URL query string. 560 561 #### Examples 562 563 564 ```coffee 565 root.unescaped = this.value.unescape_url_query() 566 567 # In: {"value":"foo+%26+bar"} 568 # Out: {"unescaped":"foo & bar"} 569 ``` 570 571 ### `unquote` 572 573 Unquotes a target string, expanding any escape sequences (`\t`, `\n`, `\xFF`, `\u0100`) for control characters and non-printable characters. 574 575 #### Examples 576 577 578 ```coffee 579 root.unquoted = this.thing.unquote() 580 581 # In: {"thing":"\"foo\\nbar\""} 582 # Out: {"unquoted":"foo\nbar"} 583 ``` 584 585 ### `uppercase` 586 587 Convert a string value into uppercase. 588 589 #### Examples 590 591 592 ```coffee 593 root.foo = this.foo.uppercase() 594 595 # In: {"foo":"hello world"} 596 # Out: {"foo":"HELLO WORLD"} 597 ``` 598 599 ## Regular Expressions 600 601 ### `re_find_all` 602 603 Returns an array containing all successive matches of a regular expression in a string. 604 605 #### Parameters 606 607 **`pattern`** <string> The pattern to match against. 608 609 #### Examples 610 611 612 ```coffee 613 root.matches = this.value.re_find_all("a.") 614 615 # In: {"value":"paranormal"} 616 # Out: {"matches":["ar","an","al"]} 617 ``` 618 619 ### `re_find_all_object` 620 621 Returns an array of objects containing all matches of the regular expression and the matches of its subexpressions. The key of each match value is the name of the group when specified, otherwise it is the index of the matching group, starting with the expression as a whole at 0. 622 623 #### Parameters 624 625 **`pattern`** <string> The pattern to match against. 626 627 #### Examples 628 629 630 ```coffee 631 root.matches = this.value.re_find_all_object("a(?P<foo>x*)b") 632 633 # In: {"value":"-axxb-ab-"} 634 # Out: {"matches":[{"0":"axxb","foo":"xx"},{"0":"ab","foo":""}]} 635 ``` 636 637 ```coffee 638 root.matches = this.value.re_find_all_object("(?m)(?P<key>\\w+):\\s+(?P<value>\\w+)$") 639 640 # In: {"value":"option1: value1\noption2: value2\noption3: value3"} 641 # Out: {"matches":[{"0":"option1: value1","key":"option1","value":"value1"},{"0":"option2: value2","key":"option2","value":"value2"},{"0":"option3: value3","key":"option3","value":"value3"}]} 642 ``` 643 644 ### `re_find_all_submatch` 645 646 Returns an array of arrays containing all successive matches of the regular expression in a string and the matches, if any, of its subexpressions. 647 648 #### Parameters 649 650 **`pattern`** <string> The pattern to match against. 651 652 #### Examples 653 654 655 ```coffee 656 root.matches = this.value.re_find_all_submatch("a(x*)b") 657 658 # In: {"value":"-axxb-ab-"} 659 # Out: {"matches":[["axxb","xx"],["ab",""]]} 660 ``` 661 662 ### `re_find_object` 663 664 Returns an object containing the first match of the regular expression and the matches of its subexpressions. The key of each match value is the name of the group when specified, otherwise it is the index of the matching group, starting with the expression as a whole at 0. 665 666 #### Parameters 667 668 **`pattern`** <string> The pattern to match against. 669 670 #### Examples 671 672 673 ```coffee 674 root.matches = this.value.re_find_object("a(?P<foo>x*)b") 675 676 # In: {"value":"-axxb-ab-"} 677 # Out: {"matches":{"0":"axxb","foo":"xx"}} 678 ``` 679 680 ```coffee 681 root.matches = this.value.re_find_object("(?P<key>\\w+):\\s+(?P<value>\\w+)") 682 683 # In: {"value":"option1: value1"} 684 # Out: {"matches":{"0":"option1: value1","key":"option1","value":"value1"}} 685 ``` 686 687 ### `re_match` 688 689 Checks whether a regular expression matches against any part of a string and returns a boolean. 690 691 #### Parameters 692 693 **`pattern`** <string> The pattern to match against. 694 695 #### Examples 696 697 698 ```coffee 699 root.matches = this.value.re_match("[0-9]") 700 701 # In: {"value":"there are 10 puppies"} 702 # Out: {"matches":true} 703 704 # In: {"value":"there are ten puppies"} 705 # Out: {"matches":false} 706 ``` 707 708 ### `re_replace` 709 710 Replaces all occurrences of the argument regular expression in a string with a value. Inside the value $ signs are interpreted as submatch expansions, e.g. `$1` represents the text of the first submatch. 711 712 #### Parameters 713 714 **`pattern`** <string> The pattern to match against. 715 **`value`** <string> The value to replace with. 716 717 #### Examples 718 719 720 ```coffee 721 root.new_value = this.value.re_replace("ADD ([0-9]+)","+($1)") 722 723 # In: {"value":"foo ADD 70"} 724 # Out: {"new_value":"foo +(70)"} 725 ``` 726 727 ## Number Manipulation 728 729 ### `abs` 730 731 Returns the absolute value of a number. 732 733 #### Examples 734 735 736 ```coffee 737 root.new_value = this.value.abs() 738 739 # In: {"value":5.3} 740 # Out: {"new_value":5.3} 741 742 # In: {"value":-5.9} 743 # Out: {"new_value":5.9} 744 ``` 745 746 ### `ceil` 747 748 Returns the least integer value greater than or equal to a number. 749 750 #### Examples 751 752 753 ```coffee 754 root.new_value = this.value.ceil() 755 756 # In: {"value":5.3} 757 # Out: {"new_value":6} 758 759 # In: {"value":-5.9} 760 # Out: {"new_value":-5} 761 ``` 762 763 ### `floor` 764 765 Returns the greatest integer value less than or equal to the target number. 766 767 #### Examples 768 769 770 ```coffee 771 root.new_value = this.value.floor() 772 773 # In: {"value":5.7} 774 # Out: {"new_value":5} 775 ``` 776 777 ### `log` 778 779 Returns the natural logarithm of a number. 780 781 #### Examples 782 783 784 ```coffee 785 root.new_value = this.value.log().round() 786 787 # In: {"value":1} 788 # Out: {"new_value":0} 789 790 # In: {"value":2.7183} 791 # Out: {"new_value":1} 792 ``` 793 794 ### `log10` 795 796 Returns the decimal logarithm of a number. 797 798 #### Examples 799 800 801 ```coffee 802 root.new_value = this.value.log10() 803 804 # In: {"value":100} 805 # Out: {"new_value":2} 806 807 # In: {"value":1000} 808 # Out: {"new_value":3} 809 ``` 810 811 ### `max` 812 813 Returns the largest numerical value found within an array. All values must be numerical and the array must not be empty, otherwise an error is returned. 814 815 #### Examples 816 817 818 ```coffee 819 root.biggest = this.values.max() 820 821 # In: {"values":[0,3,2.5,7,5]} 822 # Out: {"biggest":7} 823 ``` 824 825 ```coffee 826 root.new_value = [0,this.value].max() 827 828 # In: {"value":-1} 829 # Out: {"new_value":0} 830 831 # In: {"value":7} 832 # Out: {"new_value":7} 833 ``` 834 835 ### `min` 836 837 Returns the smallest numerical value found within an array. All values must be numerical and the array must not be empty, otherwise an error is returned. 838 839 #### Examples 840 841 842 ```coffee 843 root.smallest = this.values.min() 844 845 # In: {"values":[0,3,-2.5,7,5]} 846 # Out: {"smallest":-2.5} 847 ``` 848 849 ```coffee 850 root.new_value = [10,this.value].min() 851 852 # In: {"value":2} 853 # Out: {"new_value":2} 854 855 # In: {"value":23} 856 # Out: {"new_value":10} 857 ``` 858 859 ### `round` 860 861 Rounds numbers to the nearest integer, rounding half away from zero. 862 863 #### Examples 864 865 866 ```coffee 867 root.new_value = this.value.round() 868 869 # In: {"value":5.3} 870 # Out: {"new_value":5} 871 872 # In: {"value":5.9} 873 # Out: {"new_value":6} 874 ``` 875 876 ## Timestamp Manipulation 877 878 ### `format_timestamp` 879 880 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 881 882 Attempts to format a timestamp value as a string according to a specified format, or ISO 8601 by default. Timestamp values can either be a numerical unix time in seconds (with up to nanosecond precision via decimals), or a string in ISO 8601 format. 883 884 #### Parameters 885 886 **`format`** <string, default `"2006-01-02T15:04:05.999999999Z07:00"`> The output format to use. 887 **`tz`** <(optional) string> An optional timezone to use, otherwise the timezone of the input string is used, or in the case of unix timestamps the local timezone is used. 888 889 #### Examples 890 891 892 ```coffee 893 root.something_at = (this.created_at + 300).format_timestamp() 894 ``` 895 896 An optional string argument can be used in order to specify the output format of the timestamp. The format is defined by showing how the reference time, defined to be Mon Jan 2 15:04:05 -0700 MST 2006, would be displayed if it were the value. 897 898 ```coffee 899 root.something_at = (this.created_at + 300).format_timestamp("2006-Jan-02 15:04:05") 900 ``` 901 902 A second optional string argument can also be used in order to specify a timezone, otherwise the timezone of the input string is used, or in the case of unix timestamps the local timezone is used. 903 904 ```coffee 905 root.something_at = this.created_at.format_timestamp(format: "2006-Jan-02 15:04:05", tz: "UTC") 906 907 # In: {"created_at":1597405526} 908 # Out: {"something_at":"2020-Aug-14 11:45:26"} 909 910 # In: {"created_at":"2020-08-14T11:50:26.371Z"} 911 # Out: {"something_at":"2020-Aug-14 11:50:26"} 912 ``` 913 914 And `format_timestamp` supports up to nanosecond precision with floating point timestamp values. 915 916 ```coffee 917 root.something_at = this.created_at.format_timestamp("2006-Jan-02 15:04:05.999999", "UTC") 918 919 # In: {"created_at":1597405526.123456} 920 # Out: {"something_at":"2020-Aug-14 11:45:26.123456"} 921 922 # In: {"created_at":"2020-08-14T11:50:26.371Z"} 923 # Out: {"something_at":"2020-Aug-14 11:50:26.371"} 924 ``` 925 926 ### `format_timestamp_strftime` 927 928 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 929 930 Attempts to format a timestamp value as a string according to a specified strftime-compatible format. Timestamp values can either be a numerical unix time in seconds (with up to nanosecond precision via decimals), or a string in ISO 8601 format. 931 932 #### Parameters 933 934 **`format`** <string> The output format to use. 935 **`tz`** <(optional) string> An optional timezone to use, otherwise the timezone of the input string is used. 936 937 #### Examples 938 939 940 The format consists of zero or more conversion specifiers and ordinary characters (except `%`). All ordinary characters are copied to the output string without modification. Each conversion specification begins with `%` character followed by the character that determines the behaviour of the specifier. Please refer to [man 3 strftime](https://linux.die.net/man/3/strftime) for the list of format specifiers. 941 942 ```coffee 943 root.something_at = (this.created_at + 300).format_timestamp_strftime("%Y-%b-%d %H:%M:%S") 944 ``` 945 946 A second optional string argument can also be used in order to specify a timezone, otherwise the timezone of the input string is used, or in the case of unix timestamps the local timezone is used. 947 948 ```coffee 949 root.something_at = this.created_at.format_timestamp_strftime("%Y-%b-%d %H:%M:%S", "UTC") 950 951 # In: {"created_at":1597405526} 952 # Out: {"something_at":"2020-Aug-14 11:45:26"} 953 954 # In: {"created_at":"2020-08-14T11:50:26.371Z"} 955 # Out: {"something_at":"2020-Aug-14 11:50:26"} 956 ``` 957 958 ### `format_timestamp_unix` 959 960 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 961 962 Attempts to format a timestamp value as a unix timestamp. Timestamp values can either be a numerical unix time in seconds (with up to nanosecond precision via decimals), or a string in ISO 8601 format. The [`parse_timestamp`](#parse_timestamp) method can be used in order to parse different timestamp formats. 963 964 #### Examples 965 966 967 ```coffee 968 root.created_at_unix = this.created_at.format_timestamp_unix() 969 970 # In: {"created_at":"2009-11-10T23:00:00Z"} 971 # Out: {"created_at_unix":1257894000} 972 ``` 973 974 ### `format_timestamp_unix_nano` 975 976 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 977 978 Attempts to format a timestamp value as a unix timestamp with nanosecond precision. Timestamp values can either be a numerical unix time in seconds (with up to nanosecond precision via decimals), or a string in ISO 8601 format. The [`parse_timestamp`](#parse_timestamp) method can be used in order to parse different timestamp formats. 979 980 #### Examples 981 982 983 ```coffee 984 root.created_at_unix = this.created_at.format_timestamp_unix_nano() 985 986 # In: {"created_at":"2009-11-10T23:00:00Z"} 987 # Out: {"created_at_unix":1257894000000000000} 988 ``` 989 990 ### `parse_duration` 991 992 Attempts to parse a string as a duration and returns an integer of nanoseconds. A duration string is a possibly signed sequence of decimal numbers, each with an optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". 993 994 #### Examples 995 996 997 ```coffee 998 root.delay_for_ns = this.delay_for.parse_duration() 999 1000 # In: {"delay_for":"50us"} 1001 # Out: {"delay_for_ns":50000} 1002 ``` 1003 1004 ```coffee 1005 root.delay_for_s = this.delay_for.parse_duration() / 1000000000 1006 1007 # In: {"delay_for":"2h"} 1008 # Out: {"delay_for_s":7200} 1009 ``` 1010 1011 ### `parse_duration_iso8601` 1012 1013 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 1014 1015 Attempts to parse a string using ISO-8601 rules as a duration and returns an integer of nanoseconds. A duration string is represented by the format "P[n]Y[n]M[n]DT[n]H[n]M[n]S" or "P[n]W". In these representations, the "[n]" is replaced by the value for each of the date and time elements that follow the "[n]". For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds". The last field of the format allows fractions with one decimal place, so "P3.5S" will return 3500000000ns. Any additional decimals will be truncated. 1016 1017 #### Examples 1018 1019 1020 Arbitrary ISO-8601 duration string to nanoseconds: 1021 1022 ```coffee 1023 root.delay_for_ns = this.delay_for.parse_duration_iso8601() 1024 1025 # In: {"delay_for":"P3Y6M4DT12H30M5S"} 1026 # Out: {"delay_for_ns":110839937000000000} 1027 ``` 1028 1029 Two hours ISO-8601 duration string to seconds: 1030 1031 ```coffee 1032 root.delay_for_s = this.delay_for.parse_duration_iso8601() / 1000000000 1033 1034 # In: {"delay_for":"PT2H"} 1035 # Out: {"delay_for_s":7200} 1036 ``` 1037 1038 Two and a half seconds ISO-8601 duration string to seconds: 1039 1040 ```coffee 1041 root.delay_for_s = this.delay_for.parse_duration_iso8601() / 1000000000 1042 1043 # In: {"delay_for":"PT2.5S"} 1044 # Out: {"delay_for_s":2.5} 1045 ``` 1046 1047 ### `parse_timestamp` 1048 1049 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 1050 1051 Attempts to parse a string as a timestamp following a specified format and outputs a string following ISO 8601, which can then be fed into `format_timestamp`. The input format is defined by showing how the reference time, defined to be Mon Jan 2 15:04:05 -0700 MST 2006, would be displayed if it were the value. 1052 1053 #### Parameters 1054 1055 **`format`** <string> The format of the target string. 1056 1057 #### Examples 1058 1059 1060 ```coffee 1061 root.doc.timestamp = this.doc.timestamp.parse_timestamp("2006-Jan-02") 1062 1063 # In: {"doc":{"timestamp":"2020-Aug-14"}} 1064 # Out: {"doc":{"timestamp":"2020-08-14T00:00:00Z"}} 1065 ``` 1066 1067 ### `parse_timestamp_strptime` 1068 1069 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 1070 1071 Attempts to parse a string as a timestamp following a specified strptime-compatible format and outputs a string following ISO 8601, which can then be fed into `format_timestamp`. 1072 1073 #### Parameters 1074 1075 **`format`** <string> The format of the target string. 1076 1077 #### Examples 1078 1079 1080 The format consists of zero or more conversion specifiers and ordinary characters (except `%`). All ordinary characters are copied to the output string without modification. Each conversion specification begins with a `%` character followed by the character that determines the behaviour of the specifier. Please refer to [man 3 strptime](https://linux.die.net/man/3/strptime) for the list of format specifiers. 1081 1082 ```coffee 1083 root.doc.timestamp = this.doc.timestamp.parse_timestamp_strptime("%Y-%b-%d") 1084 1085 # In: {"doc":{"timestamp":"2020-Aug-14"}} 1086 # Out: {"doc":{"timestamp":"2020-08-14T00:00:00Z"}} 1087 ``` 1088 1089 ## Type Coercion 1090 1091 ### `bool` 1092 1093 Attempt to parse a value into a boolean. An optional argument can be provided, in which case if the value cannot be parsed the argument will be returned instead. If the value is a number then any non-zero value will resolve to `true`, if the value is a string then any of the following values are considered valid: `1, t, T, TRUE, true, True, 0, f, F, FALSE`. 1094 1095 #### Parameters 1096 1097 **`default`** <(optional) bool> An optional value to yield if the target cannot be parsed as a boolean. 1098 1099 #### Examples 1100 1101 1102 ```coffee 1103 root.foo = this.thing.bool() 1104 root.bar = this.thing.bool(true) 1105 ``` 1106 1107 ### `bytes` 1108 1109 Marshal a value into a byte array. If the value is already a byte array it is unchanged. 1110 1111 #### Examples 1112 1113 1114 ```coffee 1115 root.first_byte = this.name.bytes().index(0) 1116 1117 # In: {"name":"foobar bazson"} 1118 # Out: {"first_byte":102} 1119 ``` 1120 1121 ### `not_empty` 1122 1123 Ensures that the given string, array or object value is not empty, and if so returns it, otherwise an error is returned. 1124 1125 #### Examples 1126 1127 1128 ```coffee 1129 root.a = this.a.not_empty() 1130 1131 # In: {"a":"foo"} 1132 # Out: {"a":"foo"} 1133 1134 # In: {"a":""} 1135 # Out: Error("failed assignment (line 1): field `this.a`: string value is empty") 1136 1137 # In: {"a":["foo","bar"]} 1138 # Out: {"a":["foo","bar"]} 1139 1140 # In: {"a":[]} 1141 # Out: Error("failed assignment (line 1): field `this.a`: array value is empty") 1142 1143 # In: {"a":{"b":"foo","c":"bar"}} 1144 # Out: {"a":{"b":"foo","c":"bar"}} 1145 1146 # In: {"a":{}} 1147 # Out: Error("failed assignment (line 1): field `this.a`: object value is empty") 1148 ``` 1149 1150 ### `not_null` 1151 1152 Ensures that the given value is not `null`, and if so returns it, otherwise an error is returned. 1153 1154 #### Examples 1155 1156 1157 ```coffee 1158 root.a = this.a.not_null() 1159 1160 # In: {"a":"foobar","b":"barbaz"} 1161 # Out: {"a":"foobar"} 1162 1163 # In: {"b":"barbaz"} 1164 # Out: Error("failed assignment (line 1): field `this.a`: value is null") 1165 ``` 1166 1167 ### `number` 1168 1169 Attempt to parse a value into a number. An optional argument can be provided, in which case if the value cannot be parsed into a number the argument will be returned instead. 1170 1171 #### Parameters 1172 1173 **`default`** <(optional) float> An optional value to yield if the target cannot be parsed as a number. 1174 1175 #### Examples 1176 1177 1178 ```coffee 1179 root.foo = this.thing.number() + 10 1180 root.bar = this.thing.number(5) * 10 1181 ``` 1182 1183 ### `string` 1184 1185 Marshal a value into a string. If the value is already a string it is unchanged. 1186 1187 #### Examples 1188 1189 1190 ```coffee 1191 root.nested_json = this.string() 1192 1193 # In: {"foo":"bar"} 1194 # Out: {"nested_json":"{\"foo\":\"bar\"}"} 1195 ``` 1196 1197 ```coffee 1198 root.id = this.id.string() 1199 1200 # In: {"id":228930314431312345} 1201 # Out: {"id":"228930314431312345"} 1202 ``` 1203 1204 ### `type` 1205 1206 Returns the type of a value as a string, providing one of the following values: `string`, `bytes`, `number`, `bool`, `array`, `object` or `null`. 1207 1208 #### Examples 1209 1210 1211 ```coffee 1212 root.bar_type = this.bar.type() 1213 root.foo_type = this.foo.type() 1214 1215 # In: {"bar":10,"foo":"is a string"} 1216 # Out: {"bar_type":"number","foo_type":"string"} 1217 ``` 1218 1219 ## Object & Array Manipulation 1220 1221 ### `all` 1222 1223 Checks each element of an array against a query and returns true if all elements passed. An error occurs if the target is not an array, or if any element results in the provided query returning a non-boolean result. Returns false if the target array is empty. 1224 1225 #### Parameters 1226 1227 **`test`** <query expression> A test query to apply to each element. 1228 1229 #### Examples 1230 1231 1232 ```coffee 1233 root.all_over_21 = this.patrons.all(patron -> patron.age >= 21) 1234 1235 # In: {"patrons":[{"id":"1","age":18},{"id":"2","age":23}]} 1236 # Out: {"all_over_21":false} 1237 1238 # In: {"patrons":[{"id":"1","age":45},{"id":"2","age":23}]} 1239 # Out: {"all_over_21":true} 1240 ``` 1241 1242 ### `any` 1243 1244 Checks the elements of an array against a query and returns true if any element passes. An error occurs if the target is not an array, or if an element results in the provided query returning a non-boolean result. Returns false if the target array is empty. 1245 1246 #### Parameters 1247 1248 **`test`** <query expression> A test query to apply to each element. 1249 1250 #### Examples 1251 1252 1253 ```coffee 1254 root.any_over_21 = this.patrons.any(patron -> patron.age >= 21) 1255 1256 # In: {"patrons":[{"id":"1","age":18},{"id":"2","age":23}]} 1257 # Out: {"any_over_21":true} 1258 1259 # In: {"patrons":[{"id":"1","age":10},{"id":"2","age":12}]} 1260 # Out: {"any_over_21":false} 1261 ``` 1262 1263 ### `append` 1264 1265 Returns an array with new elements appended to the end. 1266 1267 #### Examples 1268 1269 1270 ```coffee 1271 root.foo = this.foo.append("and", "this") 1272 1273 # In: {"foo":["bar","baz"]} 1274 # Out: {"foo":["bar","baz","and","this"]} 1275 ``` 1276 1277 ### `assign` 1278 1279 Merge a source object into an existing destination object. When a collision is found within the merged structures (both a source and destination object contain the same non-object keys) the value in the destination object will be overwritten by that of source object. In order to preserve both values on collision use the [`merge`](#merge) method. 1280 1281 #### Parameters 1282 1283 **`with`** <unknown> A value to merge the target value with. 1284 1285 #### Examples 1286 1287 1288 ```coffee 1289 root = this.foo.assign(this.bar) 1290 1291 # In: {"foo":{"first_name":"fooer","likes":"bars"},"bar":{"second_name":"barer","likes":"foos"}} 1292 # Out: {"first_name":"fooer","likes":"foos","second_name":"barer"} 1293 ``` 1294 1295 ### `collapse` 1296 1297 Collapse an array or object into an object of key/value pairs for each field, where the key is the full path of the structured field in dot path notation. Empty arrays an objects are ignored by default. 1298 1299 #### Parameters 1300 1301 **`include_empty`** <bool, default `false`> Whether to include empty objects and arrays in the resulting object. 1302 1303 #### Examples 1304 1305 1306 ```coffee 1307 root.result = this.collapse() 1308 1309 # In: {"foo":[{"bar":"1"},{"bar":{}},{"bar":"2"},{"bar":[]}]} 1310 # Out: {"result":{"foo.0.bar":"1","foo.2.bar":"2"}} 1311 ``` 1312 1313 An optional boolean parameter can be set to true in order to include empty objects and arrays. 1314 1315 ```coffee 1316 root.result = this.collapse(include_empty: true) 1317 1318 # In: {"foo":[{"bar":"1"},{"bar":{}},{"bar":"2"},{"bar":[]}]} 1319 # Out: {"result":{"foo.0.bar":"1","foo.1.bar":{},"foo.2.bar":"2","foo.3.bar":[]}} 1320 ``` 1321 1322 ### `contains` 1323 1324 Checks whether an array contains an element matching the argument, or an object contains a value matching the argument, and returns a boolean result. Numerical comparisons are made irrespective of the representation type (float versus integer). 1325 1326 #### Parameters 1327 1328 **`value`** <unknown> A value to test against elements of the target. 1329 1330 #### Examples 1331 1332 1333 ```coffee 1334 root.has_foo = this.thing.contains("foo") 1335 1336 # In: {"thing":["this","foo","that"]} 1337 # Out: {"has_foo":true} 1338 1339 # In: {"thing":["this","bar","that"]} 1340 # Out: {"has_foo":false} 1341 ``` 1342 1343 ```coffee 1344 root.has_bar = this.thing.contains(20) 1345 1346 # In: {"thing":[10.3,20.0,"huh",3]} 1347 # Out: {"has_bar":true} 1348 1349 # In: {"thing":[2,3,40,67]} 1350 # Out: {"has_bar":false} 1351 ``` 1352 1353 ### `enumerated` 1354 1355 Converts an array into a new array of objects, where each object has a field index containing the `index` of the element and a field `value` containing the original value of the element. 1356 1357 #### Examples 1358 1359 1360 ```coffee 1361 root.foo = this.foo.enumerated() 1362 1363 # In: {"foo":["bar","baz"]} 1364 # Out: {"foo":[{"index":0,"value":"bar"},{"index":1,"value":"baz"}]} 1365 ``` 1366 1367 ### `explode` 1368 1369 Explodes an array or object at a [field path][field_paths]. 1370 1371 #### Parameters 1372 1373 **`path`** <string> A [dot path][field_paths] to a field to explode. 1374 1375 #### Examples 1376 1377 1378 ##### On arrays 1379 1380 Exploding arrays results in an array containing elements matching the original document, where the target field of each element is an element of the exploded array: 1381 1382 ```coffee 1383 root = this.explode("value") 1384 1385 # In: {"id":1,"value":["foo","bar","baz"]} 1386 # Out: [{"id":1,"value":"foo"},{"id":1,"value":"bar"},{"id":1,"value":"baz"}] 1387 ``` 1388 1389 ##### On objects 1390 1391 Exploding objects results in an object where the keys match the target object, and the values match the original document but with the target field replaced by the exploded value: 1392 1393 ```coffee 1394 root = this.explode("value") 1395 1396 # In: {"id":1,"value":{"foo":2,"bar":[3,4],"baz":{"bev":5}}} 1397 # Out: {"bar":{"id":1,"value":[3,4]},"baz":{"id":1,"value":{"bev":5}},"foo":{"id":1,"value":2}} 1398 ``` 1399 1400 ### `filter` 1401 1402 Executes a mapping query argument for each element of an array or key/value pair of an object. If the query returns `false` the item is removed from the resulting array or object. The item will also be removed if the query returns any non-boolean value. 1403 1404 #### Parameters 1405 1406 **`test`** <query expression> A query to apply to each element, if this query resolves to any value other than a boolean `true` the element will be removed from the result. 1407 1408 #### Examples 1409 1410 1411 ```coffee 1412 root.new_nums = this.nums.filter(num -> num > 10) 1413 1414 # In: {"nums":[3,11,4,17]} 1415 # Out: {"new_nums":[11,17]} 1416 ``` 1417 1418 ##### On objects 1419 1420 When filtering objects the mapping query argument is provided a context with a field `key` containing the value key, and a field `value` containing the value. 1421 1422 ```coffee 1423 root.new_dict = this.dict.filter(item -> item.value.contains("foo")) 1424 1425 # In: {"dict":{"first":"hello foo","second":"world","third":"this foo is great"}} 1426 # Out: {"new_dict":{"first":"hello foo","third":"this foo is great"}} 1427 ``` 1428 1429 ### `flatten` 1430 1431 Iterates an array and any element that is itself an array is removed and has its elements inserted directly in the resulting array. 1432 1433 #### Examples 1434 1435 1436 ```coffee 1437 root.result = this.flatten() 1438 1439 # In: ["foo",["bar","baz"],"buz"] 1440 # Out: {"result":["foo","bar","baz","buz"]} 1441 ``` 1442 1443 ### `fold` 1444 1445 Takes two arguments: an initial value, and a mapping query. For each element of an array the mapping context is an object with two fields `tally` and `value`, where `tally` contains the current accumulated value and `value` is the value of the current element. The mapping must return the result of adding the value to the tally. 1446 1447 The first argument is the value that `tally` will have on the first call. 1448 1449 #### Parameters 1450 1451 **`initial`** <unknown> The initial value to start the fold with. For example, an empty object `{}`, a zero count `0`, or an empty string `""`. 1452 **`query`** <query expression> A query to apply for each element. The query is provided an object with two fields; `tally` containing the current tally, and `value` containing the value of the current element. The query should result in a new tally to be passed to the next element query. 1453 1454 #### Examples 1455 1456 1457 ```coffee 1458 root.sum = this.foo.fold(0, item -> item.tally + item.value) 1459 1460 # In: {"foo":[3,8,11]} 1461 # Out: {"sum":22} 1462 ``` 1463 1464 ```coffee 1465 root.result = this.foo.fold("", item -> "%v%v".format(item.tally, item.value)) 1466 1467 # In: {"foo":["hello ", "world"]} 1468 # Out: {"result":"hello world"} 1469 ``` 1470 1471 You can use fold to merge an array of objects together: 1472 1473 ```coffee 1474 root.smoothie = this.fruits.fold({}, item -> item.tally.merge(item.value)) 1475 1476 # In: {"fruits":[{"apple":5},{"banana":3},{"orange":8}]} 1477 # Out: {"smoothie":{"apple":5,"banana":3,"orange":8}} 1478 ``` 1479 1480 ### `get` 1481 1482 Extract a field value, identified via a [dot path][field_paths], from an object. 1483 1484 #### Parameters 1485 1486 **`path`** <string> A [dot path][field_paths] identifying a field to obtain. 1487 1488 #### Examples 1489 1490 1491 ```coffee 1492 root.result = this.foo.get(this.target) 1493 1494 # In: {"foo":{"bar":"from bar","baz":"from baz"},"target":"bar"} 1495 # Out: {"result":"from bar"} 1496 1497 # In: {"foo":{"bar":"from bar","baz":"from baz"},"target":"baz"} 1498 # Out: {"result":"from baz"} 1499 ``` 1500 1501 ### `index` 1502 1503 Extract an element from an array by an index. The index can be negative, and if so the element will be selected from the end counting backwards starting from -1. E.g. an index of -1 returns the last element, an index of -2 returns the element before the last, and so on. 1504 1505 #### Parameters 1506 1507 **`index`** <integer> The index to obtain from an array. 1508 1509 #### Examples 1510 1511 1512 ```coffee 1513 root.last_name = this.names.index(-1) 1514 1515 # In: {"names":["rachel","stevens"]} 1516 # Out: {"last_name":"stevens"} 1517 ``` 1518 1519 It is also possible to use this method on byte arrays, in which case the selected element will be returned as an integer. 1520 1521 ```coffee 1522 root.last_byte = this.name.bytes().index(-1) 1523 1524 # In: {"name":"foobar bazson"} 1525 # Out: {"last_byte":110} 1526 ``` 1527 1528 ### `join` 1529 1530 Join an array of strings with an optional delimiter into a single string. 1531 1532 #### Parameters 1533 1534 **`delimiter`** <(optional) string> An optional delimiter to add between each string. 1535 1536 #### Examples 1537 1538 1539 ```coffee 1540 root.joined_words = this.words.join() 1541 root.joined_numbers = this.numbers.map_each(this.string()).join(",") 1542 1543 # In: {"words":["hello","world"],"numbers":[3,8,11]} 1544 # Out: {"joined_numbers":"3,8,11","joined_words":"helloworld"} 1545 ``` 1546 1547 ### `json_schema` 1548 1549 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 1550 1551 Checks a [JSON schema](https://json-schema.org/) against a value and returns the value if it matches or throws and error if it does not. 1552 1553 #### Parameters 1554 1555 **`schema`** <string> The schema to check values against. 1556 1557 #### Examples 1558 1559 1560 ```coffee 1561 root = this.json_schema("""{ 1562 "type":"object", 1563 "properties":{ 1564 "foo":{ 1565 "type":"string" 1566 } 1567 } 1568 }""") 1569 1570 # In: {"foo":"bar"} 1571 # Out: {"foo":"bar"} 1572 1573 # In: {"foo":5} 1574 # Out: Error("failed assignment (line 1): field `this`: foo invalid type. expected: string, given: integer") 1575 ``` 1576 1577 In order to load a schema from a file use the `file` function. 1578 1579 ```coffee 1580 root = this.json_schema(file(var("BENTHOS_TEST_BLOBLANG_SCHEMA_FILE"))) 1581 ``` 1582 1583 ### `key_values` 1584 1585 Returns the key/value pairs of an object as an array, where each element is an object with a `key` field and a `value` field. The order of the resulting array will be random. 1586 1587 #### Examples 1588 1589 1590 ```coffee 1591 root.foo_key_values = this.foo.key_values().sort_by(pair -> pair.key) 1592 1593 # In: {"foo":{"bar":1,"baz":2}} 1594 # Out: {"foo_key_values":[{"key":"bar","value":1},{"key":"baz","value":2}]} 1595 ``` 1596 1597 ### `keys` 1598 1599 Returns the keys of an object as an array. 1600 1601 #### Examples 1602 1603 1604 ```coffee 1605 root.foo_keys = this.foo.keys() 1606 1607 # In: {"foo":{"bar":1,"baz":2}} 1608 # Out: {"foo_keys":["bar","baz"]} 1609 ``` 1610 1611 ### `length` 1612 1613 Returns the length of an array or object (number of keys). 1614 1615 #### Examples 1616 1617 1618 ```coffee 1619 root.foo_len = this.foo.length() 1620 1621 # In: {"foo":["first","second"]} 1622 # Out: {"foo_len":2} 1623 1624 # In: {"foo":{"first":"bar","second":"baz"}} 1625 # Out: {"foo_len":2} 1626 ``` 1627 1628 ### `map_each` 1629 1630 1631 1632 #### Parameters 1633 1634 **`query`** <query expression> A query that will be used to map each element. 1635 1636 #### Examples 1637 1638 1639 ##### On arrays 1640 1641 Apply a mapping to each element of an array and replace the element with the result. Within the argument mapping the context is the value of the element being mapped. 1642 1643 ```coffee 1644 root.new_nums = this.nums.map_each(num -> if num < 10 { 1645 deleted() 1646 } else { 1647 num - 10 1648 }) 1649 1650 # In: {"nums":[3,11,4,17]} 1651 # Out: {"new_nums":[1,7]} 1652 ``` 1653 1654 ##### On objects 1655 1656 Apply a mapping to each value of an object and replace the value with the result. Within the argument mapping the context is an object with a field `key` containing the value key, and a field `value`. 1657 1658 ```coffee 1659 root.new_dict = this.dict.map_each(item -> item.value.uppercase()) 1660 1661 # In: {"dict":{"foo":"hello","bar":"world"}} 1662 # Out: {"new_dict":{"bar":"WORLD","foo":"HELLO"}} 1663 ``` 1664 1665 ### `map_each_key` 1666 1667 Apply a mapping to each key of an object, and replace the key with the result, which must be a string. 1668 1669 #### Parameters 1670 1671 **`query`** <query expression> A query that will be used to map each key. 1672 1673 #### Examples 1674 1675 1676 ```coffee 1677 root.new_dict = this.dict.map_each_key(key -> key.uppercase()) 1678 1679 # In: {"dict":{"keya":"hello","keyb":"world"}} 1680 # Out: {"new_dict":{"KEYA":"hello","KEYB":"world"}} 1681 ``` 1682 1683 ```coffee 1684 root = this.map_each_key(key -> if key.contains("kafka") { "_" + key }) 1685 1686 # In: {"amqp_key":"foo","kafka_key":"bar","kafka_topic":"baz"} 1687 # Out: {"_kafka_key":"bar","_kafka_topic":"baz","amqp_key":"foo"} 1688 ``` 1689 1690 ### `merge` 1691 1692 Merge a source object into an existing destination object. When a collision is found within the merged structures (both a source and destination object contain the same non-object keys) the result will be an array containing both values, where values that are already arrays will be expanded into the resulting array. In order to simply override destination fields on collision use the [`assign`](#assign) method. 1693 1694 #### Parameters 1695 1696 **`with`** <unknown> A value to merge the target value with. 1697 1698 #### Examples 1699 1700 1701 ```coffee 1702 root = this.foo.merge(this.bar) 1703 1704 # In: {"foo":{"first_name":"fooer","likes":"bars"},"bar":{"second_name":"barer","likes":"foos"}} 1705 # Out: {"first_name":"fooer","likes":["bars","foos"],"second_name":"barer"} 1706 ``` 1707 1708 ### `slice` 1709 1710 Extract a slice from an array by specifying two indices, a low and high bound, which selects a half-open range that includes the first element, but excludes the last one. If the second index is omitted then it defaults to the length of the input sequence. 1711 1712 #### Parameters 1713 1714 **`low`** <integer> The low bound, which is the first element of the selection, or if negative selects from the end. 1715 **`high`** <(optional) integer> An optional high bound. 1716 1717 #### Examples 1718 1719 1720 ```coffee 1721 root.beginning = this.value.slice(0, 2) 1722 root.end = this.value.slice(4) 1723 1724 # In: {"value":["foo","bar","baz","buz","bev"]} 1725 # Out: {"beginning":["foo","bar"],"end":["bev"]} 1726 ``` 1727 1728 A negative low index can be used, indicating an offset from the end of the sequence. If the low index is greater than the length of the sequence then an empty result is returned. 1729 1730 ```coffee 1731 root.last_chunk = this.value.slice(-2) 1732 root.the_rest = this.value.slice(0, -2) 1733 1734 # In: {"value":["foo","bar","baz","buz","bev"]} 1735 # Out: {"last_chunk":["buz","bev"],"the_rest":["foo","bar","baz"]} 1736 ``` 1737 1738 ### `sort` 1739 1740 Attempts to sort the values of an array in increasing order. The type of all values must match in order for the ordering to succeed. Supports string and number values. 1741 1742 #### Parameters 1743 1744 **`compare`** <(optional) query expression> An optional query that should explicitly compare elements `left` and `right` and provide a boolean result. 1745 1746 #### Examples 1747 1748 1749 ```coffee 1750 root.sorted = this.foo.sort() 1751 1752 # In: {"foo":["bbb","ccc","aaa"]} 1753 # Out: {"sorted":["aaa","bbb","ccc"]} 1754 ``` 1755 1756 It's also possible to specify a mapping argument, which is provided an object context with fields `left` and `right`, the mapping must return a boolean indicating whether the `left` value is less than `right`. This allows you to sort arrays containing non-string or non-number values. 1757 1758 ```coffee 1759 root.sorted = this.foo.sort(item -> item.left.v < item.right.v) 1760 1761 # In: {"foo":[{"id":"foo","v":"bbb"},{"id":"bar","v":"ccc"},{"id":"baz","v":"aaa"}]} 1762 # Out: {"sorted":[{"id":"baz","v":"aaa"},{"id":"foo","v":"bbb"},{"id":"bar","v":"ccc"}]} 1763 ``` 1764 1765 ### `sort_by` 1766 1767 Attempts to sort the elements of an array, in increasing order, by a value emitted by an argument query applied to each element. The type of all values must match in order for the ordering to succeed. Supports string and number values. 1768 1769 #### Parameters 1770 1771 **`query`** <query expression> A query to apply to each element that yields a value used for sorting. 1772 1773 #### Examples 1774 1775 1776 ```coffee 1777 root.sorted = this.foo.sort_by(ele -> ele.id) 1778 1779 # In: {"foo":[{"id":"bbb","message":"bar"},{"id":"aaa","message":"foo"},{"id":"ccc","message":"baz"}]} 1780 # Out: {"sorted":[{"id":"aaa","message":"foo"},{"id":"bbb","message":"bar"},{"id":"ccc","message":"baz"}]} 1781 ``` 1782 1783 ### `sum` 1784 1785 Sum the numerical values of an array. 1786 1787 #### Examples 1788 1789 1790 ```coffee 1791 root.sum = this.foo.sum() 1792 1793 # In: {"foo":[3,8,4]} 1794 # Out: {"sum":15} 1795 ``` 1796 1797 ### `unique` 1798 1799 Attempts to remove duplicate values from an array. The array may contain a combination of different value types, but numbers and strings are checked separately (`"5"` is a different element to `5`). 1800 1801 #### Parameters 1802 1803 **`emit`** <(optional) query expression> An optional query that can be used in order to yield a value for each element to determine uniqueness. 1804 1805 #### Examples 1806 1807 1808 ```coffee 1809 root.uniques = this.foo.unique() 1810 1811 # In: {"foo":["a","b","a","c"]} 1812 # Out: {"uniques":["a","b","c"]} 1813 ``` 1814 1815 ### `values` 1816 1817 Returns the values of an object as an array. The order of the resulting array will be random. 1818 1819 #### Examples 1820 1821 1822 ```coffee 1823 root.foo_vals = this.foo.values().sort() 1824 1825 # In: {"foo":{"bar":1,"baz":2}} 1826 # Out: {"foo_vals":[1,2]} 1827 ``` 1828 1829 ### `without` 1830 1831 Returns an object where one or more [field path][field_paths] arguments are removed. Each path specifies a specific field to be deleted from the input object, allowing for nested fields. 1832 1833 If a key within a nested path does not exist or is not an object then it is not removed. 1834 1835 #### Examples 1836 1837 1838 ```coffee 1839 root = this.without("inner.a","inner.c","d") 1840 1841 # In: {"inner":{"a":"first","b":"second","c":"third"},"d":"fourth","e":"fifth"} 1842 # Out: {"e":"fifth","inner":{"b":"second"}} 1843 ``` 1844 1845 ## Parsing 1846 1847 ### `bloblang` 1848 1849 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 1850 1851 Executes an argument Bloblang mapping on the target. This method can be used in order to execute dynamic mappings. Imports and functions that interact with the environment, such as `file` and `env`, or that access message information directly, such as `content` or `json`, are not enabled for dynamic Bloblang mappings. 1852 1853 #### Parameters 1854 1855 **`mapping`** <string> The mapping to execute. 1856 1857 #### Examples 1858 1859 1860 ```coffee 1861 root.body = this.body.bloblang(this.mapping) 1862 1863 # In: {"body":{"foo":"hello world"},"mapping":"root.foo = this.foo.uppercase()"} 1864 # Out: {"body":{"foo":"HELLO WORLD"}} 1865 1866 # In: {"body":{"foo":"hello world 2"},"mapping":"root.foo = this.foo.capitalize()"} 1867 # Out: {"body":{"foo":"Hello World 2"}} 1868 ``` 1869 1870 ### `format_json` 1871 1872 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 1873 1874 Serializes a target value into a pretty-printed JSON byte array (with 4 space indentation by default). 1875 1876 #### Parameters 1877 1878 **`indent`** <(optional) string, default `" "`> Indentation string. Each element in a JSON object or array will begin on a new, indented line followed by one or more copies of indent according to the indentation nesting. 1879 1880 #### Examples 1881 1882 1883 ```coffee 1884 root = this.doc.format_json() 1885 1886 # In: {"doc":{"foo":"bar"}} 1887 # Out: { 1888 # "foo": "bar" 1889 # } 1890 ``` 1891 1892 Provide an argument string in order to customise the indentation used. 1893 1894 ```coffee 1895 root = this.format_json(" ") 1896 1897 # In: {"doc":{"foo":"bar"}} 1898 # Out: { 1899 # "doc": { 1900 # "foo": "bar" 1901 # } 1902 # } 1903 ``` 1904 1905 Use the `.string()` method in order to coerce the result into a string. 1906 1907 ```coffee 1908 root.doc = this.doc.format_json().string() 1909 1910 # In: {"doc":{"foo":"bar"}} 1911 # Out: {"doc":"{\n \"foo\": \"bar\"\n}"} 1912 ``` 1913 1914 ### `format_msgpack` 1915 1916 Formats data as a [MessagePack](https://msgpack.org/) message in bytes format. 1917 1918 #### Examples 1919 1920 1921 ```coffee 1922 root = this.format_msgpack().encode("hex") 1923 1924 # In: {"foo":"bar"} 1925 # Out: 81a3666f6fa3626172 1926 ``` 1927 1928 ```coffee 1929 root.encoded = this.format_msgpack().encode("base64") 1930 1931 # In: {"foo":"bar"} 1932 # Out: {"encoded":"gaNmb2+jYmFy"} 1933 ``` 1934 1935 ### `format_yaml` 1936 1937 Serializes a target value into a YAML byte array. 1938 1939 #### Examples 1940 1941 1942 ```coffee 1943 root = this.doc.format_yaml() 1944 1945 # In: {"doc":{"foo":"bar"}} 1946 # Out: foo: bar 1947 ``` 1948 1949 Use the `.string()` method in order to coerce the result into a string. 1950 1951 ```coffee 1952 root.doc = this.doc.format_yaml().string() 1953 1954 # In: {"doc":{"foo":"bar"}} 1955 # Out: {"doc":"foo: bar\n"} 1956 ``` 1957 1958 ### `parse_csv` 1959 1960 Attempts to parse a string into an array of objects by following the CSV format described in RFC 4180. The first line is assumed to be a header row, which determines the keys of values in each object. 1961 1962 #### Examples 1963 1964 1965 ```coffee 1966 root.orders = this.orders.parse_csv() 1967 1968 # In: {"orders":"foo,bar\nfoo 1,bar 1\nfoo 2,bar 2"} 1969 # Out: {"orders":[{"bar":"bar 1","foo":"foo 1"},{"bar":"bar 2","foo":"foo 2"}]} 1970 ``` 1971 1972 ### `parse_json` 1973 1974 Attempts to parse a string as a JSON document and returns the result. 1975 1976 #### Examples 1977 1978 1979 ```coffee 1980 root.doc = this.doc.parse_json() 1981 1982 # In: {"doc":"{\"foo\":\"bar\"}"} 1983 # Out: {"doc":{"foo":"bar"}} 1984 ``` 1985 1986 ### `parse_msgpack` 1987 1988 Parses a [MessagePack](https://msgpack.org/) message into a structured document. 1989 1990 #### Examples 1991 1992 1993 ```coffee 1994 root = content().decode("hex").parse_msgpack() 1995 1996 # In: 81a3666f6fa3626172 1997 # Out: {"foo":"bar"} 1998 ``` 1999 2000 ```coffee 2001 root = this.encoded.decode("base64").parse_msgpack() 2002 2003 # In: {"encoded":"gaNmb2+jYmFy"} 2004 # Out: {"foo":"bar"} 2005 ``` 2006 2007 ### `parse_xml` 2008 2009 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 2010 2011 Attempts to parse a string as an XML document and returns a structured result, where elements appear as keys of an object according to the following rules: 2012 2013 - If an element contains attributes they are parsed by prefixing a hyphen, `-`, to the attribute label. 2014 - If the element is a simple element and has attributes, the element value is given the key `#text`. 2015 - XML comments, directives, and process instructions are ignored. 2016 - When elements are repeated the resulting JSON value is an array. 2017 - If cast is true, try to cast values to numbers and booleans instead of returning strings. 2018 2019 #### Parameters 2020 2021 **`cast`** <(optional) bool> whether to try to cast values that are numbers and booleans to the right type. default: false 2022 2023 #### Examples 2024 2025 2026 ```coffee 2027 root.doc = this.doc.parse_xml() 2028 2029 # In: {"doc":"<root><title>This is a title</title><content>This is some content</content></root>"} 2030 # Out: {"doc":{"root":{"content":"This is some content","title":"This is a title"}}} 2031 ``` 2032 2033 ```coffee 2034 root.doc = this.doc.parse_xml(cast: false) 2035 2036 # In: {"doc":"<root><title>This is a title</title><number id=99>123</number><bool>True</bool></root>"} 2037 # Out: {"doc":{"root":{"bool":"True","number":{"#text":"123","-id":"99"},"title":"This is a title"}}} 2038 ``` 2039 2040 ```coffee 2041 root.doc = this.doc.parse_xml(cast: true) 2042 2043 # In: {"doc":"<root><title>This is a title</title><number id=99>123</number><bool>True</bool></root>"} 2044 # Out: {"doc":{"root":{"bool":true,"number":{"#text":123,"-id":99},"title":"This is a title"}}} 2045 ``` 2046 2047 ### `parse_yaml` 2048 2049 Attempts to parse a string as a single YAML document and returns the result. 2050 2051 #### Examples 2052 2053 2054 ```coffee 2055 root.doc = this.doc.parse_yaml() 2056 2057 # In: {"doc":"foo: bar"} 2058 # Out: {"doc":{"foo":"bar"}} 2059 ``` 2060 2061 ## Encoding and Encryption 2062 2063 ### `decode` 2064 2065 Decodes an encoded string target according to a chosen scheme and returns the result as a byte array. When mapping the result to a JSON field the value should be cast to a string using the method [`string`][methods.string], or encoded using the method [`encode`][methods.encode], otherwise it will be base64 encoded by default. 2066 2067 Available schemes are: `base64`, `base64url`, `hex`, `ascii85`. 2068 2069 #### Parameters 2070 2071 **`scheme`** <string> The decoding scheme to use. 2072 2073 #### Examples 2074 2075 2076 ```coffee 2077 root.decoded = this.value.decode("hex").string() 2078 2079 # In: {"value":"68656c6c6f20776f726c64"} 2080 # Out: {"decoded":"hello world"} 2081 ``` 2082 2083 ```coffee 2084 root = this.encoded.decode("ascii85") 2085 2086 # In: {"encoded":"FD,B0+DGm>FDl80Ci\"A>F`)8BEckl6F`M&(+Cno&@/"} 2087 # Out: this is totally unstructured data 2088 ``` 2089 2090 ### `decrypt_aes` 2091 2092 Decrypts an encrypted string or byte array target according to a chosen AES encryption method and returns the result as a byte array. The algorithms require a key and an initialization vector / nonce. Available schemes are: `ctr`, `ofb`, `cbc`. 2093 2094 #### Parameters 2095 2096 **`scheme`** <string> The scheme to use for decryption, one of `ctr`, `ofb`, `cbc`. 2097 **`key`** <string> A key to decrypt with. 2098 **`iv`** <string> An initialization vector / nonce. 2099 2100 #### Examples 2101 2102 2103 ```coffee 2104 let key = "2b7e151628aed2a6abf7158809cf4f3c".decode("hex") 2105 let vector = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff".decode("hex") 2106 root.decrypted = this.value.decode("hex").decrypt_aes("ctr", $key, $vector).string() 2107 2108 # In: {"value":"84e9b31ff7400bdf80be7254"} 2109 # Out: {"decrypted":"hello world!"} 2110 ``` 2111 2112 ### `encode` 2113 2114 Encodes a string or byte array target according to a chosen scheme and returns a string result. Available schemes are: `base64`, `base64url`, `hex`, `ascii85`. 2115 2116 #### Parameters 2117 2118 **`scheme`** <string> The encoding scheme to use. 2119 2120 #### Examples 2121 2122 2123 ```coffee 2124 root.encoded = this.value.encode("hex") 2125 2126 # In: {"value":"hello world"} 2127 # Out: {"encoded":"68656c6c6f20776f726c64"} 2128 ``` 2129 2130 ```coffee 2131 root.encoded = content().encode("ascii85") 2132 2133 # In: this is totally unstructured data 2134 # Out: {"encoded":"FD,B0+DGm>FDl80Ci\"A>F`)8BEckl6F`M&(+Cno&@/"} 2135 ``` 2136 2137 ### `encrypt_aes` 2138 2139 Encrypts a string or byte array target according to a chosen AES encryption method and returns a string result. The algorithms require a key and an initialization vector / nonce. Available schemes are: `ctr`, `ofb`, `cbc`. 2140 2141 #### Parameters 2142 2143 **`scheme`** <string> The scheme to use for encryption, one of `ctr`, `ofb`, `cbc`. 2144 **`key`** <string> A key to encrypt with. 2145 **`iv`** <string> An initialization vector / nonce. 2146 2147 #### Examples 2148 2149 2150 ```coffee 2151 let key = "2b7e151628aed2a6abf7158809cf4f3c".decode("hex") 2152 let vector = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff".decode("hex") 2153 root.encrypted = this.value.encrypt_aes("ctr", $key, $vector).encode("hex") 2154 2155 # In: {"value":"hello world!"} 2156 # Out: {"encrypted":"84e9b31ff7400bdf80be7254"} 2157 ``` 2158 2159 ### `hash` 2160 2161 Hashes a string or byte array according to a chosen algorithm and returns the result as a byte array. When mapping the result to a JSON field the value should be cast to a string using the method [`string`][methods.string], or encoded using the method [`encode`][methods.encode], otherwise it will be base64 encoded by default. 2162 2163 Available algorithms are: `hmac_sha1`, `hmac_sha256`, `hmac_sha512`, `md5`, `sha1`, `sha256`, `sha512`, `xxhash64`. 2164 2165 The following algorithms require a key, which is specified as a second argument: `hmac_sha1`, `hmac_sha256`, `hmac_sha512`. 2166 2167 #### Parameters 2168 2169 **`algorithm`** <string> The hasing algorithm to use. 2170 **`key`** <(optional) string> An optional key to use. 2171 2172 #### Examples 2173 2174 2175 ```coffee 2176 root.h1 = this.value.hash("sha1").encode("hex") 2177 root.h2 = this.value.hash("hmac_sha1","static-key").encode("hex") 2178 2179 # In: {"value":"hello world"} 2180 # Out: {"h1":"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed","h2":"d87e5f068fa08fe90bb95bc7c8344cb809179d76"} 2181 ``` 2182 2183 ## GeoIP 2184 2185 ### `geoip_anonymous_ip` 2186 2187 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the anonymous IP associated with it. 2188 2189 #### Parameters 2190 2191 **`path`** <string> A path to an mmdb (maxmind) file. 2192 2193 ### `geoip_asn` 2194 2195 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the ASN associated with it. 2196 2197 #### Parameters 2198 2199 **`path`** <string> A path to an mmdb (maxmind) file. 2200 2201 ### `geoip_city` 2202 2203 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the city associated with it. 2204 2205 #### Parameters 2206 2207 **`path`** <string> A path to an mmdb (maxmind) file. 2208 2209 ### `geoip_connection_type` 2210 2211 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the connection type associated with it. 2212 2213 #### Parameters 2214 2215 **`path`** <string> A path to an mmdb (maxmind) file. 2216 2217 ### `geoip_country` 2218 2219 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the country associated with it. 2220 2221 #### Parameters 2222 2223 **`path`** <string> A path to an mmdb (maxmind) file. 2224 2225 ### `geoip_domain` 2226 2227 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the domain associated with it. 2228 2229 #### Parameters 2230 2231 **`path`** <string> A path to an mmdb (maxmind) file. 2232 2233 ### `geoip_enterprise` 2234 2235 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the enterprise associated with it. 2236 2237 #### Parameters 2238 2239 **`path`** <string> A path to an mmdb (maxmind) file. 2240 2241 ### `geoip_isp` 2242 2243 EXPERIMENTAL: Looks up an IP address against a [MaxMind database file](https://www.maxmind.com/en/home) and, if found, returns an object describing the ISP associated with it. 2244 2245 #### Parameters 2246 2247 **`path`** <string> A path to an mmdb (maxmind) file. 2248 2249 ## Deprecated 2250 2251 ### `parse_timestamp_unix` 2252 2253 Attempts to parse a string as a timestamp, following ISO 8601 format by default, and returns the unix epoch. 2254 2255 #### Parameters 2256 2257 **`format`** <string, default `"2006-01-02T15:04:05.999999999Z07:00"`> An optional format to use. 2258 2259 #### Examples 2260 2261 2262 ```coffee 2263 root.doc.timestamp = this.doc.timestamp.parse_timestamp_unix() 2264 2265 # In: {"doc":{"timestamp":"2020-08-14T11:45:26.371Z"}} 2266 # Out: {"doc":{"timestamp":1597405526}} 2267 ``` 2268 2269 An optional string argument can be used in order to specify the expected format of the timestamp. The format is defined by showing how the reference time, defined to be Mon Jan 2 15:04:05 -0700 MST 2006, would be displayed if it were the value. 2270 2271 ```coffee 2272 root.doc.timestamp = this.doc.timestamp.parse_timestamp_unix("2006-Jan-02") 2273 2274 # In: {"doc":{"timestamp":"2020-Aug-14"}} 2275 # Out: {"doc":{"timestamp":1597363200}} 2276 ``` 2277 2278 [field_paths]: /docs/configuration/field_paths 2279 [methods.encode]: #encode 2280 [methods.string]: #string