Skip to main content

Writing JSON files

Start by importing scalaql:

import scalaql._

// Docs classes
import scalaql.docs.Hogwarts._
import scalaql.docs.DocUtils._

// Imports for examples
import java.nio.file.Paths
import io.circe.generic.auto._

Basic write​

In this example, we'll read an existing JSON file, process it and write the result into a new CSV file.
Input file:

val studentsPath = Paths.get("docs/src/main/resources/students.json")
// studentsPath: java.nio.file.Path = docs/src/main/resources/students.json

printFile(studentsPath)
// {"name":"Harry","age":19,"faculty":"Gryffindor","grade":85.1,"specialization":"learning","birthDay":"1980-07-31"}
// {"name":"Ron","age":18,"faculty":"Gryffindor","grade":66.2,"specialization":"eating","birthDay":"1980-05-01"}
// {"name":"Hermione","age":18,"faculty":"Gryffindor","grade":99.6,"specialization":"learning","birthDay":"1979-09-17"}
// {"name":"Draco","age":18,"faculty":"Slytherin","grade":85.1,"specialization":"trolling","birthDay":"1980-06-05"}
// {"name":"Cedric","age":17,"faculty":"Hufflepuff","grade":90.1,"specialization":"young dying","birthDay":"1977-10-01"}

First, define an aggregation Query:

case class FacultyInfo(
name: String,
avgAge: Double,
totalGrade: Double)

val aggregation: Query[From[Student], FacultyInfo] =
select[Student]
.groupBy(_.faculty)
.aggregate((faculty, students) =>
(
students.avgBy(_.age.toDouble) &&
students.sumBy(_.grade)
).map{ case (avgAge, totalGrade) => FacultyInfo(faculty, avgAge, totalGrade) }
)
// aggregation: Query[From[Student], FacultyInfo] = FROM(Hogwarts::Student) -> GROUP BY(String) -> AGGREGATE(MdocSession::App::FacultyInfo)

Then you could write the result into a CSV file as follows:

val outPath = Paths.get("docs/target/stats.json")
// outPath: java.nio.file.Path = docs/target/stats.json

aggregation
.foreach(
json.write[FacultyInfo].file(outPath)
)
.run(
from(
json.read[Student].file(studentsPath)
)
)

It will generate a CSV file with the following content:

printFile(outPath)
// {"name":"Gryffindor","avgAge":18.333333333333332,"totalGrade":250.9}
// {"name":"Slytherin","avgAge":18.0,"totalGrade":85.1}
// {"name":"Hufflepuff","avgAge":17.0,"totalGrade":90.1}
//

Single line​

You could also customize the resulting JSON file format.
By default, it writes each JSON document into a separate file line.

Alternatively, you could write them into a single array.

Start with the following imports:

import scalaql._

// Docs classes
import scalaql.docs.Hogwarts._
import scalaql.docs.DocUtils._

// Imports for examples
import java.nio.file.Paths
import io.circe.generic.auto._

With the same aggregation query:

case class FacultyInfo(
name: String,
avgAge: Double,
totalGrade: Double)

val aggregation: Query[From[Student], FacultyInfo] =
select[Student]
.groupBy(_.faculty)
.aggregate((faculty, students) =>
(
students.avgBy(_.age.toDouble) &&
students.sumBy(_.grade)
).map{ case (avgAge, totalGrade) => FacultyInfo(faculty, avgAge, totalGrade) }
)
// aggregation: Query[From[Student], FacultyInfo] = FROM(Hogwarts::Student) -> GROUP BY(String) -> AGGREGATE(MdocSession::App3::FacultyInfo)

This is how to produce a JSON file with array:

val studentsPath = Paths.get("docs/src/main/resources/students.json")
// studentsPath: java.nio.file.Path = docs/src/main/resources/students.json
val outPathArray = Paths.get("docs/target/stats_array.json")
// outPathArray: java.nio.file.Path = docs/target/stats_array.json

aggregation
.foreach(
json
.write[FacultyInfo]
.option(multiline = false)
.file(outPathArray)
)
.run(
from(
json.read[Student].file(studentsPath)
)
)

It will produce the following JSON file:

printFile(outPathArray)
// [
// {
// "name" : "Gryffindor",
// "avgAge" : 18.333333333333332,
// "totalGrade" : 250.9
// },
// {
// "name" : "Slytherin",
// "avgAge" : 18.0,
// "totalGrade" : 85.1
// },
// {
// "name" : "Hufflepuff",
// "avgAge" : 17.0,
// "totalGrade" : 90.1
// }
// ]