I am new to Scala and please help me out. I have 2 Json file. I want to sort first json with a key from the second json.
For eg: First Json
{ "id": 1, "response" : [{ "user_id" : 1, "products" : [ { "product_id": 10, "price": 200 }, { "product_id": 13, "price": 210 }, { "product_id": 9, "price": 320 } ] },{ "user_id" : 2, "products" : [ { "product_id": 15, "price": 200 }, { "product_id": 13, "price": 210 }, { "product_id": 8, "price": 320 } ] } ] }
And My Second Json
{ "sort": [ { "user_id": 1, "products": [ { "id": 8, "rank": 5 }, { "id": 9, "rank": 1 }, { "id": 10, "rank": 3 }, { "id": 13, "rank": 2 },{ "id": 15, "rank": 6 },{ "id": 17, "rank": 4 },{ "id": 20, "rank": 7 },{ "id": 21, "rank": 8 },{ "id": 23, "rank": 9 } ] },{ "user_id": 2, "products": [ { "id": 8, "rank": 5 }, { "id": 9, "rank": 1 }, { "id": 10, "rank": 3 }, { "id": 13, "rank": 2 },{ "id": 15, "rank": 6 },{ "id": 17, "rank": 4 },{ "id": 20, "rank": 7 },{ "id": 21, "rank": 8 },{ "id": 23, "rank": 9 } ] } ] }
I want to sort my first json with respect to the rank I have in second Json.
Output should be like each user should have his products in sorted order based on the rank that is specified for each user on the second JSON.
This is so far what I have tried
def sortedRes() = Action.async { val url = //1st json url val sortUrl = //2nd json url ws.url(url).get().map { response => val value: JsValue = Json.parse(response.body) val result: Either[Exception, SampleResponses] = value.validate[SampleResponses] match { case JsSuccess(searchResponse, _) => Right(searchResponse) case JsError(errors) => Left(new Exception("Couldn't parse Search API response")) } val values: List[SampleResponse] = result.right.get.responses ws.url(sortUrl).get().map { response => val sorted: JsValue = Json.parse(response.body) val sortRespResult: Either[Exception, Sort] = sorted.validate[Sort] match { case JsSuccess(sortResponse, _) => Right(sortResponse) case JsError(errors) => Left(new Exception("Couldn't parse because of these errors : " + errors)) } val prodRankDetails: List[SampleRank] = sortRespResult.right.get.sort println("prod = " + prodRankDetails.head.products.sortWith(_.rank > _.rank)) } Ok(Json.toJson(result.right.get)) } }
In the last print statement I got the second json's first users product sorted. What I am trying to get is my first json sorted based on the second user.
Here is my model class
package models import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json._ // Combinator syntax object sample { case class SampleProduct(productId:Int, price: Int) case class SampleResponse(userId: Int, products: List[SampleProduct]) case class SampleResponses(id: Int, responses: List[SampleResponse]) case class SampleRankedProduct(id: Int, rank: Int) case class SampleRank(userId: Int, products: List[SampleRankedProduct]) case class Sort(sort: List[SampleRank]) implicit val productReads: Reads[SampleProduct] = ( (JsPath \ "product_id").read[Int] and (JsPath \ "price").read[Int] )(SampleProduct.apply _) implicit val productWrites: Writes[SampleProduct] = ( (JsPath \ "product_id").write[Int] and (JsPath \ "price ").write[Int] )(unlift(SampleProduct.unapply)) implicit val responseReads: Reads[SampleResponse] = ( (JsPath \ "user_id").read[Int] and (JsPath \ "products").read[List[SampleProduct]] )(SampleResponse.apply _) implicit val responseWrites: Writes[SampleResponse] = ( (JsPath \ "user_id").write[Int] and (JsPath \ "products").write[List[SampleProduct]] )(unlift(SampleResponse.unapply)) implicit val responsesReads: Reads[SampleResponses] = ( (JsPath \ "id").read[Int] and (JsPath \ "response").read[List[SampleResponse]] )(SampleResponses.apply _) implicit val responsesWrites: Writes[SampleResponses] = ( (JsPath \ "id").write[Int] and (JsPath \ "response").write[List[SampleResponse]] )(unlift(SampleResponses.unapply)) implicit val rankedProductReads: Reads[SampleRankedProduct] = ( (JsPath \ "id").read[Int] and (JsPath \ "rank").read[Int] )(SampleRankedProduct.apply _) implicit val rankedProductWrites: Writes[SampleRankedProduct] = ( (JsPath \ "id").write[Int] and (JsPath \ "rank ").write[Int] )(unlift(SampleRankedProduct.unapply)) implicit val rankReads: Reads[SampleRank] = ( (JsPath \ "user_id").read[Int] and (JsPath \ "products").read[List[SampleRankedProduct]] )(SampleRank.apply _) implicit val rankWrites: Writes[SampleRank] = ( (JsPath \ "user_id").write[Int] and (JsPath \ "products").write[List[SampleRankedProduct]] )(unlift(SampleRank.unapply)) implicit val sortReads: Reads[Sort] = (JsPath \ "sort").read[List[SampleRank]].map(x ⇒ Sort(x)) implicit val sortWrites: Writes[Sort] = (__ \ "sort").write[List[SampleRank]].contramap { (person: Sort) => person.sort } }
1 Answers
Answers 1
An approach for sorting the first JSON using the ranking from the second one, is something like that:
.... val prodRankDetails: List[SampleRank] = sortRespResult.right.get.sort val sortedResults = values.copy( responses = values.responses.map { resultForUser => val rankingForUser = prodRankDetails .find(_.userId == resultForUser.userId) .getOrElse(throw new RuntimeException(s"Rank not found for user ${resultForUser.userId}")) .products .map(product => (product.id, product.rank)) .toMap resultForUser.copy( products = resultForUser.products.sortWith((a, b) => rankingForUser.getOrElse(a.productId, Int.MaxValue) < rankingForUser.getOrElse(b.productId, Int.MaxValue)) ) } ) Ok(Json.toJson(sortedResults))
that should be performed just after you got prodRankDetails
. And also the response will be available inside the .map
as you are managing a Future
. So you have to move also the Ok(...)
inside that map and to flatMap
the outer Future
.
Hope this helps.
0 comments:
Post a Comment