use JsLookup for multiple level array using play Json for lists with objects and simple lists - scala

i have a function that exctract from a json list of elements based on the path i give it.
the func looks like this:
def findAllValuesAtPath(jsValue: JsObject, path: String): List[JsValue] = {
val jsPath = JsPath(path
.split("\\[\\*]\\.")
.flatMap(s => s.split("\\.")
.map(RecursiveSearch)
).toList)
jsPath(jsValue)
}
for example:
{
"person": {
"kids": [
{
"name": "josh",
"age": 5
},
{
"name": "julia",
"age": 13
}
]
}
}
now if i give the path - "person.kids[*].name" I will get list of their names List("josh", "julia") which its what i want.
but if the list of kids were just simple list like:
{
"person": {
"kids": [
"josh",
"julia"
]
}
}
and i will give the path - "person.kids[*]" I will get empty list List() and I want to get this as List("josh", "julia") (without the brakets)
do you see any way to improve my func to handle both cases?

Related

MongoDB - How to update if and only if all ids are matching inside a list's object

Lets say I have an Object in MongoDB that looks like this:
"obj":
{
"list":
[
{ "_id": "123" },
{ "_id": "456" },
],
"result": 42
}
Lets say I have an Event Object (happens to be in Kotlin, but do not mind the programming language):
class Event(val ids: Set<String>, val newResult: Int)
How to construct an update query in MongoDB to set the result if and only if the ids in the Event Object match the ids inside the list.

Filtering vales in Dataweave

I am trying to filter out vales matching a variable using dataweave.
result = {
"drives": [{
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
}, {
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}]
}
above is my payload.
Am trying below code
%dw 2.0
output application/json
---
{
drives: payload.result.drives[0] filter ((item, index) -> item.name == "QA")
}
which gives me error
error:
You called the function 'Value Selector' with these arguments:
1: String ("{"drives":[{"id":"0AEBByqXZ0xb4Uk9PVA","name":"QA-zz-SFJobs-Contact...)
2: Name ("drives")
But it expects one of these combinations:
(Array, Name)
(Array, String)
(Date, Name)
(DateTime, Name)
(LocalDateTime, Name)
(LocalTime, Name)
(Object, Name)
(Object, String)
(Period, Name)
(Time, Name)
5| drives: payload.result.drives[0] filter ((item, index) -> item.name == vars.folderName)
^^^^^^^^^^^^^^^^^^^^^
Trace:
at filter (line: 5, column: 13)
at main (line: 5, column: 38)" evaluating expression: "%dw 2.0
output application/json
{
drives: payload.result.drives[0] filter ((item, index) -> item.name == vars.folderName)
}".
Expected output:
{
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}
how can i achieve this?
The input should be a valid "JSON" like :
{
"result": {
"drives": [{
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
},
{
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}]
}
}
Here applying the logic above :
{
drives: payload.result.drives[0]
}
returns output as :
{
"drives": {
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
}
}
which is a single object containing object, and hence filter method cannot be applied as filter is applicable on arrays and arrays of objects.
To try your dataweave code snippet you can use the online dataweave editor :
Online Dataweave Editor
which can give you better insights.
As #Bibek mentioned, you need a properly formatted json as input:
{
"result": {
"drives": [{
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
},
{
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}]
}
}
And then you can use filter on an array (drives), so your query would be:
%dw 2.0
output application/json
---
payload.result.drives filter ((item, index) -> item.name == "QA")
If you use "drives[0]" you are selecting the first element in the array, so, you don't need to use filter (unless the first element also contains an array inside of it, which is not the case)

Decode a nested array with circe-optics

I have JSON like this:
"data": {
"project": {
"activityChildren": [
{
"id": 2,
"parents": [
{
"id": 1
}
]
},
]
}
}
I'd like to decode this to List[(Long, List[Long])] with circe-optics. I got as far as:
val activityParents: Map[Long, List[Long]] = root.data.activityChildren.each.json
.getAll(json)
.flatMap { activity =>
root.id.long.getOption(activity).map(_ -> root.parents.each.long.getAll(activity))
}
.toMap
I wonder whether it's possible to define a single lens for this that just turns the JSON into the desired map without explicitly mapping over the intermediate array. If so, how?

Can we skip documents in MongoDB Map Reduce based on the values computed in reduce?

In mapReduce function of Mongo, can we skip storing a document with the out option.
Eg:
Sample Documents - animals -
{
"type": "bird",
"value": "10"
},
{
"type": "fish",
"value": "30"
},
{
"type": "fish",
"value": "20"
},
{
"type": "plant",
"value": "40"
}
Map reduce functions
function map() {
emit(this.type, this.value);
}
function reduce(key, value) {
var total = Array.sum(value);
// --> IF total is less than 20 then skip
if (total < 20) {
// skip... Maybe something like returning null? --> Is something like this possible?
return;
}
return total;
}
db.animals.mapReduce(map, reduce, { out: 'mr_test' })
I tried searching for a solution around this in the documentation and I wasn't able to find it. Can anyone help me with this?
No you cannot but you can always delete documents from the out collection:
db.mr_test.deleteMany({ value: { $lt:20 } })

[json4s]:Extracting Array of different objects

I am using the facebook graph API and the responses look similar to this:
{
"data": [
{
"id": "311620272349920_311718615673419",
"from": {
"id": "1456046457993048",
"name": "Richard Ettinson"
},
"to": {
"data": [
{
"id": "311620272349920",
"name": "Barbara Fallerman"
}
]
},
"with_tags": {
"data": [
{
"id": "311620272349920",
"name": "Barbara Fallerman"
}
]
},
"message": "I was gong out with her",
"actions": [
{
"name": "Comment",
"link": "https://www.facebook.com/311620272349920/posts/311718615673419"
},
{
"name": "Like",
"link": "https://www.facebook.com/311620272349920/posts/311718615673419"
}
]
}
I managed to for example extract the from field through
val extracted = (json \ "data" \"from").extract[PostFrom]
But I worry that if I use this technique I will need to pass over the Json multiple times to extract all the values I need which could lead to a bad performance.
How exactly could I extract these fields into case classes from the array of non similar objects?
I tried with the following case classes:
abstract class BaseResponse()
case class Data(list:List[Post])
case class Post(id: String, post: PostFrom) extends BaseResponse
case class PostFrom(id: String, name:String)
Which always lead to an empty List, is there a way to get back a Data class which has a list of certain classes which I am interested in? (As example the top level id, from and with_tags)
A possibility I found was to use more case classes instead of inheritance:
case class Root[T](data:Option[T])
case class Post(id: String, from: From, message: String)
case class From(id: String, name:String)
Basically there has to be a root object which takes some kind of graphs response object, additionally it is optional so that it won't throw an exception if there was a problem with the parsing of the response.
I then used it in the following way:
val body = r.entity.asString
val json = parse(r.entity.asString)
val root = json.extract[Root[Post]]
root.data match {
case Some(post) =>
val tagger = Tagger(post.from.id, post.from.name, post.id, post.message)
log.info(s"We received $tagger")
originalSender ! RetrievedTagger(tagger)
case None => originalSender ! NoTaggerFound
}