Skip to content
Closed
16 changes: 13 additions & 3 deletions R/pkg/R/functions.R
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ NULL
#'
#' @param x Column to compute on. Note the difference in the following methods:
#' \itemize{
#' \item \code{to_json}: it is the column containing the struct or array of the structs.
#' \item \code{to_json}: it is the column containing the struct, array of the structs,
#' the map or array of maps.
#' \item \code{from_json}: it is the column containing the JSON string.
#' }
#' @param ... additional argument(s). In \code{to_json} and \code{from_json}, this contains
Expand Down Expand Up @@ -1700,8 +1701,9 @@ setMethod("to_date",
})

#' @details
#' \code{to_json}: Converts a column containing a \code{structType} or array of \code{structType}
#' into a Column of JSON string. Resolving the Column can fail if an unsupported type is encountered.
#' \code{to_json}: Converts a column containing a \code{structType}, array of \code{structType},
#' a \code{mapType} or array of \code{mapType} into a Column of JSON string.
#' Resolving the Column can fail if an unsupported type is encountered.
#'
#' @rdname column_collection_functions
#' @aliases to_json to_json,Column-method
Expand All @@ -1715,6 +1717,14 @@ setMethod("to_date",
#'
#' # Converts an array of structs into a JSON array
#' df2 <- sql("SELECT array(named_struct('name', 'Bob'), named_struct('name', 'Alice')) as people")
#' df2 <- mutate(df2, people_json = to_json(df2$people))
#'
#' # Converts a map into a JSON object
#' df2 <- sql("SELECT map('name', 'Bob')) as people")
#' df2 <- mutate(df2, people_json = to_json(df2$people))
#'
#' # Converts an array of maps into a JSON array
#' df2 <- sql("SELECT array(map('name', 'Bob'), map('name', 'Alice')) as people")
#' df2 <- mutate(df2, people_json = to_json(df2$people))}
#' @note to_json since 2.2.0
setMethod("to_json", signature(x = "Column"),
Expand Down
8 changes: 8 additions & 0 deletions R/pkg/tests/fulltests/test_sparkSQL.R
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,14 @@ test_that("column functions", {
j <- collect(select(df, alias(to_json(df$people), "json")))
expect_equal(j[order(j$json), ][1], "[{\"name\":\"Bob\"},{\"name\":\"Alice\"}]")

df <- sql("SELECT map('name', 'Bob') as people")
j <- collect(select(df, alias(to_json(df$people), "json")))
expect_equal(j[order(j$json), ][1], "{\"name\":\"Bob\"}")

df <- sql("SELECT array(map('name', 'Bob'), map('name', 'Alice')) as people")
j <- collect(select(df, alias(to_json(df$people), "json")))
expect_equal(j[order(j$json), ][1], "[{\"name\":\"Bob\"},{\"name\":\"Alice\"}]")

df <- read.json(mapTypeJsonPath)
j <- collect(select(df, alias(to_json(df$info), "json")))
expect_equal(j[order(j$json), ][1], "{\"age\":16,\"height\":176.5}")
Expand Down
22 changes: 16 additions & 6 deletions python/pyspark/sql/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1884,9 +1884,9 @@ def json_tuple(col, *fields):
@since(2.1)
def from_json(col, schema, options={}):
"""
Parses a column containing a JSON string into a [[StructType]] or [[ArrayType]]
of [[StructType]]s with the specified schema. Returns `null`, in the case of an unparseable
string.
Parses a column containing a JSON string into a :class:`StructType` or :class:`ArrayType`
of :class:`StructType`\\s with the specified schema. Returns `null`, in the case of an
unparseable string.

:param col: string column in json format
:param schema: a StructType or ArrayType of StructType to use when parsing the json column.
Expand Down Expand Up @@ -1921,10 +1921,12 @@ def from_json(col, schema, options={}):
@since(2.1)
def to_json(col, options={}):
"""
Converts a column containing a [[StructType]] or [[ArrayType]] of [[StructType]]s into a
JSON string. Throws an exception, in the case of an unsupported type.
Converts a column containing a :class:`StructType`, :class:`ArrayType` of
:class:`StructType`\\s, a :class:`MapType` or :class:`ArrayType` of :class:`MapType`\\s
into a JSON string. Throws an exception, in the case of an unsupported type.

:param col: name of column containing the struct or array of the structs
:param col: name of column containing the struct, array of the structs, the map or
array of the maps.
:param options: options to control converting. accepts the same options as the json datasource

>>> from pyspark.sql import Row
Expand All @@ -1937,6 +1939,14 @@ def to_json(col, options={}):
>>> df = spark.createDataFrame(data, ("key", "value"))
>>> df.select(to_json(df.value).alias("json")).collect()
[Row(json=u'[{"age":2,"name":"Alice"},{"age":3,"name":"Bob"}]')]
>>> data = [(1, {"name": "Alice"})]
>>> df = spark.createDataFrame(data, ("key", "value"))
>>> df.select(to_json(df.value).alias("json")).collect()
[Row(json=u'{"name":"Alice"}')]
>>> data = [(1, [{"name": "Alice"}, {"name": "Bob"}])]
>>> df = spark.createDataFrame(data, ("key", "value"))
>>> df.select(to_json(df.value).alias("json")).collect()
[Row(json=u'[{"name":"Alice"},{"name":"Bob"}]')]
"""

sc = SparkContext._active_spark_context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -618,13 +618,13 @@ case class JsonToStructs(
{"time":"26/08/2015"}
> SELECT _FUNC_(array(named_struct('a', 1, 'b', 2));
[{"a":1,"b":2}]
> SELECT _FUNC_(map('a',named_struct('b',1)));
> SELECT _FUNC_(map('a', named_struct('b', 1)));
{"a":{"b":1}}
> SELECT _FUNC_(map(named_struct('a',1),named_struct('b',2)));
> SELECT _FUNC_(map(named_struct('a', 1),named_struct('b', 2)));
{"[1]":{"b":2}}
> SELECT _FUNC_(map('a',1));
> SELECT _FUNC_(map('a', 1));
{"a":1}
> SELECT _FUNC_(array((map('a',1))));
> SELECT _FUNC_(array((map('a', 1))));
[{"a":1}]
""",
since = "2.2.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private[sql] class JacksonGenerator(
private type ValueWriter = (SpecializedGetters, Int) => Unit

// `JackGenerator` can only be initialized with a `StructType` or a `MapType`.
require(dataType.isInstanceOf[StructType] | dataType.isInstanceOf[MapType],
require(dataType.isInstanceOf[StructType] || dataType.isInstanceOf[MapType],
"JacksonGenerator only supports to be initialized with a StructType " +
s"or MapType but got ${dataType.simpleString}")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ Extended Usage:
{"time":"26/08/2015"}
> SELECT to_json(array(named_struct('a', 1, 'b', 2));
[{"a":1,"b":2}]
> SELECT to_json(map('a',named_struct('b',1)));
> SELECT to_json(map('a', named_struct('b', 1)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you committed unrelated change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or you forget to commit json-functions.sql?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

umm. I modified ExpressionDescription of StructsToJson at @HyukjinKwon 's suggestions which didn't be merged in last PR. Here's the test for describe function extended to_json, so I needed to regenerate the golden file for it. So this change isn't from json-functions.sql.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I see.

{"a":{"b":1}}
> SELECT to_json(map(named_struct('a',1),named_struct('b',2)));
> SELECT to_json(map(named_struct('a', 1),named_struct('b', 2)));
{"[1]":{"b":2}}
> SELECT to_json(map('a',1));
> SELECT to_json(map('a', 1));
{"a":1}
> SELECT to_json(array((map('a',1))));
> SELECT to_json(array((map('a', 1))));
[{"a":1}]

Since: 2.2.0
Expand Down