Parse nested maps in a function (gatling) - scala

I have a map like this:
{
"user":
{
"name": "Jon Doe",
"age": "6",
"birthdate": {
"timestamp": 1456424096
},
"gender": "M"
}
}
and a function like this
def setUser(user: Map[String, Any]): Map[String, Any]={
var usr = Map("name"-> user.get("name").getOrElse(""),
"gender" -> user.get("gender").getOrElse(""),
"age" -> user.get("age").getOrElse(""),
"birthday" -> patient.get("birthdate"))
return usr
}
And I want to have the value of "timestamp" (1456424096) mapped in the "birthday" field.
For now I have this : Some%28%7Btimestamp%3D1456424096%7D%29
I'm very new to this. Can someone help me get the value of "timestamp"?

Assuming that you want just to get rid of nested birthday (not nested user) it can look like that:
val oldData: Map[String, Any] = Map(
"user" -> Map(
"name" -> "John Doe",
"age" -> 6,
"birthday" -> Map("timestamp" -> 1234454666),
"gender" -> "M"
)
)
def flattenBirthday(userMap: Map[String, Any]) = Map(
"user" -> (userMap("user").asInstanceOf[Map[String, Any]] + (
"birthday" -> userMap("user").asInstanceOf[Map[String, Any]]("birthday").asInstanceOf[Map[String, Any]]("timestamp")
))
)
val newData = flattenBirthday(oldData)
But in general dealing with nested immutable maps will be ugly. If you extract that data from JSONs (like in your example) it is better to use some library to deserialize that data into case class objects.

Related

Filter out empty Map from a Seq[Map]

I have this Seq[Map[String,String]] :
Seq(Map("Name"-> "Laura", "City" -> "Paris"), Map("Country" -> "Italy"), Map())
I want to remove the empty Map so I can obtain:
Seq(Map("Name"-> "Laura", "City" -> "Paris"), Map("Country" -> "Italy"))
How do I do that please?
val data = Seq(Map("Name"-> "Laura", "City" -> "Paris"), Map("Country" -> "Italy"), Map())
val dataWithoutEmptyMaps = data.filter(_.nonEmpty)

Scala merge list of maps

Input =
val data = List(
Map("id" -> "123", "name" -> "raju",
"sub" -> List(Map("id" -> "english", "status" -> 2))),
Map("id" -> "123", "name" -> "raju",
"sub" -> List(Map("id" -> "english", "status" -> 0),
Map("id" -> "hindi", "status" -> 0))))
Expected Output:
val data = List(
Map("id" -> "123", "name" -> "raju",
"sub" -> List(Map("id" -> "english", "status" -> 2),
Map("id" -> "hindi", "status" -> 1),
Map("id" -> "english", "status" -> 0),
Map("id" -> "hindi", "status" -> 0))))
I'm trying to merge the "sub" key values into a list without removing the old keys but I couldn't able to get it. can anyone please help with this using scala.
Start by creating some case classes. It is much easier to work with these than with maps.
case class Person(id: String, name: String, sub: List[Language])
case class Language(id: String, status: Int)
Now, create a list of Person:
val data = List(
Person("123", "raju", List(Language("english", 2))),
Person("123", "raju", List(Language("english", 0), Language("hindi", 0))))
I don't know what your merging logic is, but let's say you just want to concatenate the sub-lists for persons with the same ID. You could do it this way:
// Gets a map from ID to the list of persons with that ID
data.groupBy(_.id)
// Gets a List[List[Person]] (the values of the map)
.values
// Makes a new Person out of the inner list of persons, concatenating all the languages of that person.
.map(persons => Person(
persons.head.id,
persons.head.name,
persons.flatMap(_.sub)))
Here is example that works on pure Maps/Lists like in your example.
val data = List(
Map("id" -> "123", "name" -> "raju",
"sub" -> List(Map("id" -> "english", "status" -> 2))),
Map("id" -> "123", "name" -> "raju",
"sub" -> List(Map("id" -> "english", "status" -> 0),
Map("id" -> "hindi", "status" -> 0))))
val expected = List(
Map("id" -> "123", "name" -> "raju",
"sub" -> List(Map("id" -> "english", "status" -> 2),
Map("id" -> "hindi", "status" -> 1),
Map("id" -> "english", "status" -> 0),
Map("id" -> "hindi", "status" -> 0))))
val res = data.groupBy(x => (x.get("id"), x.get("name"))).collect { case (_, items) =>
items.reduceLeft { (l, r) =>
l.updated("sub", l("sub").asInstanceOf[List[_]] ++ r("sub").asInstanceOf[List[_]])
}
}
println(res)
https://scalafiddle.io/sf/FBj4Mvi/0
PS: To be honest creating typed structure (as proposed by others) is probably still better sollution.

Represent nested parameters for Neo4j query in Scala

I tried to run Neo4j queries with parameters in the form of the Map[String, Anyref] which works just fine. However, I would like to send the data to Neo4j in form of the batch so the result would be Map[String, Map[String,AnyRef]] or Map[String, AnyRef] if the data is converted. But overall I would like to set the data in such a way:
{
"nodes": [
{
"id": 193331567,
"lat": 40.7599983215332,
"lon": -73.98999786376953
},
{
"id": 173062762,
"lat": 41.959999084472656,
"lon": -87.66000366210938
},
{
"id": 66276172,
"lat": 40.72999954223633,
"lon": -74.01000213623047
}
]
}
I wrote it in Scala using nested maps, however, when I pass this nested maps as a parameter to the query it cannot be rendered by Neo4j. So how can I represent this nested JSON structure in Scala? Should I use and Object instead or something like that?
Here is the map I set up:
val paramsList = Map("nodes" -> {
data map { seq =>
Map(
"lat" -> seq(1).toDouble.asInstanceOf[AnyRef],
"lon" -> seq(2).toDouble.asInstanceOf[AnyRef],
"id" -> seq(0).toInt.asInstanceOf[AnyRef]
)
}}.asInstanceOf[AnyRef])
val queryResults = neo4jSession.run(neo4jQuery, params.asJava)
It was important to convert both maps to java.util.Map so Neo4j would be able to pass this data as a parameter.
val paramsList = data map { seq =>
Map(
"lat" -> seq(1).toDouble.asInstanceOf[AnyRef],
"lon" -> seq(2).toDouble.asInstanceOf[AnyRef],
"id" -> seq(0).toInt.asInstanceOf[AnyRef]
).asJava.asInstanceOf[AnyRef]
}
val queryResults = neo4jSession.run(neo4jQueries.searchQueryWithBatchParams, Map("nodes" -> paramsList.asJava.asInstanceOf[AnyRef]).asJava)

Array query in Scala and ReactiveMongo?

I have a MongoDB collection whose documents look like this:
{
"name" : "fabio",
"items" : [
{
"id" : "1",
"word" : "xxxx"
},
{
"id" : "2",
"word" : "yyyy"
}
]
}
Now, given one name and one id, I want to retrieve "name" and the corresponding "word".
I query it like this and it seems to work:
val query = BSONDocument("name" -> name, "items.id" -> id)
But then, how do I access the value of "word"? I can get the name using this reader:
The reader for this object is like this:
implicit object UserReader extends BSONDocumentReader[User] {
def read(doc: BSONDocument): User = {
val name = doc.getAs[String]("name").get
// how do I retrive the value of "word"?
User(id, word)
}
}
But I am very confused about "word".
Additionally, because I am only interested in two fields, how should I filter the query? The following doesn't seem to work.
val filter = BSONDocument("name" -> 1, "items.$.word" -> 1)
Thanks for your help!

nested pull with scala mongodb casbah

lets say i have a simple object
{
"id":"xyz"
"answers" : [{
"name" : "Yes",
}, {
"name" : "No",
}]
}
I want to remove answer Yes from the array
I'm trying something like this without much luck:
import com.mongodb.casbah.MongoCollection
val searchObject = MongoDBObject("id"->"xyz");
getCollection().update(searchObject,$pull( "answers" -> ( "name" -> "Yes")));
You need to declare ("name" -> "Yes") as a MongoDBObject because look at:
scala> $pull( "answers" -> ( "name" -> "Yes"))
res10: com.mongodb.casbah.query.Imports.DBObject = { "$pull" : { "answers" : [ "name" , "Yes"]}}
Which is not what you want, you want to pull a subdocument:
scala> $pull ( "answers" -> MongoDBObject("name" -> "Yes") )
res11: com.mongodb.casbah.query.Imports.DBObject = { "$pull" : { "answers" : { "name" : "Yes"}}}