I work with scala play and I use WS to make get a response from an URL.
My JSON example :
[
{
"object": "001",
"object-description": "MODEL",
"criterion": "TW3",
"criterion-description": "MODELE X07"
},
{
"object": "002",
"object-description": "TYPE",
"criterion": "STANDA",
"criterion-description": "STANDARD TYPE"
}, ...
I want to get only "criterion" field where "object" equal "002". So, in this example the value "STANDA".
A Test:
ws.url(
url)
.get()
.map { response =>
Right((response.json \ "object="002"" \\ "criterion").map(_.as[String]))
}
How I can do that ?
Thanks for your help.
Your can transform the whole response into scala classes using automated formatters and then operate on those.
case class Data(`object`: String, criterion: String)
implicit val dataRead = Json.reads[Data]
response.json.as[List[Data]]
.filter(_.`object` == "002")
.map(_.criterion)
Related
I have a MongoDB entity that has a list of tags:
#Document
#TypeAlias("project")
data class Project(#Id var id: String?,
val name: String,
val tags: MutableList<Tag>)
I would like to look for Project's containing a subset of the tags.
For example given these proyects:
projectService.save(Project(null, "someProject11",
mutableListOf(Tag("area","IT"), Tag("department","Architecture"))))
projectService.save(Project(null, "someProject12",
mutableListOf(Tag("area","IT"), Tag("department","HR"))))
If I define my repository as follows:
interface ProjectRepository : ReactiveCrudRepository<Project, String> {
fun findByTags(tags : List<Tag>): Flux<Project>
}
Looking for a subset doesn't work, e.g: projects with Tag("area","IT") should return two results but actually returns 0. The underlying mongo query is:
{"find": "project", "filter": {"tags": [{"key": "area", "value": "IT"}]}
It only works passing the complete content of the list listOf(Tag("area","IT"), Tag("department","Architecture")):
{"find": "project", "filter": {"tags": [{"key": "area", "value": "IT"},{"key": "department", "value": "Architecture"}]}
How can I query for entities containing a subset of the list?
Solved using Criteria and the $elemMatch operator:
interface CustomProjectRepository {
fun findByTags(tags: List<Tag>): Flux<Project>
}
class CustomProjectRepositoryImpl(private val mongoTemplate: ReactiveMongoTemplate) : CustomProjectRepository {
override fun findByTags(tags: List<Tag>): Flux<Project> {
val query = Query()
val criterias = mutableListOf<Criteria>()
tags.forEach {
criterias.add(Criteria.where("tags").elemMatch(Criteria.where("key").`is`(it.key).and("value").`is`(it.value)))
}
query.addCriteria(Criteria().andOperator(* criterias.toTypedArray()))
return mongoTemplate.find(query, Project::class.java)
}
}
interface ProjectRepository : ReactiveCrudRepository<Project, String>, CustomProjectRepository {
fun findByClientIdAndId(clientId: String, id: String): Mono<Project>
fun findByClientId(clientId: String): Flux<Project>
}
How can I read a JSON file into a Map, using Scala. I've been trying to accomplish this but the JSON I am reading is nested JSon and I have not found a way to easily extract the JSON into keys because of that. Scala seems to be wanting to also convert the nested JSON String into an object. Instead, I want the nested JSON as a String "value". I am hoping someone can clarify or give me a hint on how I might do this.
My JSON source might look something like this:
{
"authKey": "34534645645653455454363",
"member": {
"memberId": "whatever",
"firstName": "Jon",
"lastName": "Doe",
"address": {
"line1": "Whatever Rd",
"city": "White Salmon",
"state": "WA",
"zip": "98672"
},
"anotherProp": "wahtever",
}
}
I want to extract this JSON into a Map of 2 keys without drilling into the nested JSON. Is this possible? Once I have the Map, my intention is to add the key-values to my POST request headers, like so:
val sentHeaders = Map("Content-Type" -> "application/javascript",
"Accept" -> "text/html", "authKey" -> extractedValue,
"member" -> theMemberInfoAsStringJson)
http("Custom headers")
.post("myUrl")
.headers(sentHeaders)
Since the question is tagged 'gatling', behind the curtains this lib depends on Jackson/fasterxml for JSON processing, so we can make use of it.
There is no way to retrieve a nested structured part of JSON as String directly, but with very few additional code the result can still be achieved.
So, having the input JSON:
val json = """{
| "authKey": "34534645645653455454363",
| "member": {
| "memberId": "whatever",
| "firstName": "Jon",
| "lastName": "Doe",
| "address": {
| "line1": "Whatever Rd",
| "city": "White Salmon",
| "state": "WA",
| "zip": "98672"
| },
| "anotherProp": "wahtever"
| }
|}""".stripMargin
A Jackson's ObjectMapper can be created and configured for use in Scala:
// import com.fasterxml.jackson.module.scala.DefaultScalaModule
val mapper = new ObjectMapper().registerModule(DefaultScalaModule)
To parse the input json easily, a dedicated case class is useful:
case class SrcJson(authKey: String, member: Any) {
val memberAsString = mapper.writeValueAsString(member)
}
We also include val memberAsString in it, which will contain our target JSON string, obtained through a reverse conversion from initially parsed member which actually is a Map.
Now, to parse the input json:
val parsed = mapper.readValue(json, classOf[SrcJson])
The references parsed.authKey and parsed.memberAsString will contain the researched values.
have a look at the scala play library - it has support for handling JSON. From what you describe, it should be pretty straightforward to read in the JSON and get the string value from any desired node.
Scala Play - JSON
I have a question about Gatling.
I need to get the following response:
[
{
"id": 1,
"name": "Jack"
},
{
"id": 2,
"name": "John"
}
]
grab those ids, iterate over them and make a new request for each of them.
So far I have this:
.exec(
http("Image list")
.get("/api/img")
.headers(headers_0)
.check(
jsonPath("$..id").findAll.saveAs("imgs")
)
)
It successfuly saves ids to "imgs" which is session variable but I am not able to iterate over them or process it at all. How can I process it? I am new to Gatling and Scala so I have no idea how to approach this. Please help.
You can treat the imgs session variable as a Scala List:
val ids = session("imgs").as[List[Int]]
ids.foreach(id => ...)
An update to reflect the fact that the internal implementation is now a Vector, as OP has discovered:
val ids = session("imgs").as[Seq[Int]]
I found a solution.
The only possible format is Seq. In my case this solves the problem:
val imageIds = session("imgs").as[Seq[String]]
If I have an incoming JSON of following structure
[
{
"personId" : 12,
"name": "John Doe",
"age": 48,
"birthdate": "12/1/1954",
"relationships": [
{
"relationType":"parentOf",
"value" : "Johnny walker"
},
{
"relationType":"sonOf",
"value" : "Charles Smith"
}
]
},
{
"personId" : 13,
"name": "Merry Christmas",
"age": 28,
"birthdate": "12/1/1985",
"relationships": [
{
"relationType":"sisteOf",
"value" : "Will Smith"
},
{
"relationType":"cousinOf",
"value" : "Brad Pitt"
}
]
}
]
And requirement is that for each Person record controller will have to carve out relationships array and store each record from it in a separate relationship table with personId association while persisting this incoming JSON.
And subsequently when querying these persons records system will have to lookup relationships for each person from relationships table and inject them to form the same above looking JSON to give back to UI for rendering.
What's the best efficient way to perform this "carve out" and later "inject" operations using Play framework in Scala? (using Slick in persistent layer APIs) I have looked at this JSON transformation link and json.pickBranch in there but not quite sure if that'll be fully applicable here for "carve out" and "inject" use cases for preparing JSON shown in the example. are there any elegant ideas?
One way, which is pretty straightforward, is to use case classes along with Play Json inceptions
import play.api.libs.json.Json
case class Relationship(relationType: String, value: String)
object Relationship {
implicit val RelationshipFormatter = Json.format[Relationship]
}
case class Person(personId: String, name: String, age: Int, birthdate: String, relationships: Seq[Relationship]) {
def withRelationships(relationship: Seq[Relationship]) = copy(relationships = relationships ++ relationship)
}
object Person {
implicit val PersonFormatter = Json.format[Person]
}
Now you can convert a json value to Person by using the following code, provided that jsValue is a json value of type JsValue (which in play controllers you can get by request.body.asJson):
Json.fromJson[Person](jsValue)
In Play controllers, you can
For converting a Person to json you can use the following code provided that person is a value of type Person in your context:
Json.toJson(person)
The only remaining thing is your Slick schemas which is pretty straight forward.
One option is to use a simple schema for Person, without relations and one schema for Relation with a foreign key to Person table. Then you need to find all relations associated with a specific Person, namely person and then append them to that person by calling the withRelationships method which gives you a new Person which you can serve as json:
val person = .... // find person
val relations = .... // find relationships associated with this person
val json = Json.toJson(person.withRelationships(relations))
I am using BigQuery from Scala. I tried the sample Scala code to call Google bigQuery API
Scala:
val queryInfo: QueryRequest =
new QueryRequest().setQuery(s"SELECT * FROM $PROJECT_ID:$dataSetId.$tableId;")
val queryRequest: Bigquery#Jobs#Query =
bigquery.jobs().query(PROJECT_ID, queryInfo)
val queryResponse: QueryResponse =
queryRequest.execute()
Above BQ returns:
{
"jobComplete":true,
"jobReference":{
"jobId":"job_xxx",
"projectId":"xxx"
},
"kind":"bigquery#queryResponse",
"rows":[{"f":[{"v":"1"},{"v":"1364206559422"}]}],
"schema": {
"fields":[
{"mode":"NULLABLE","name":"id","type":"STRING"},
{"mode":"NULLABLE","name":"timestamp","type":"INTEGER"}
]
},
"totalRows":"1",
"pageToken":"xxxx"
}
Please help me parse the values from above the results in JSON Format or change the query to return the result of the format like this:
{"id": "1", "timestamp": "1364206559422"}
I like lift json.
Look at the lotto example, it's straight forward with case classes