Elastic search, watcher access dotted field names in the result set - json

I created a query for a elastic search watcher setup. The result set looks like this:
"_index": "transaction_broker-2017.09.15",
"_type": "transaction_broker",
"_id": "AV6Fn_UQ9KbnKce40avY",
"_score": 3.8539968,
"_source": {
"tbroker.workitem.sync_check.tbroker_value": 7000,
"source": "/logs/web/tomcat/tbroker.log.json",
"type": "transaction_broker",
"tbroker.job.instance_id": "lixporta-p00.xxxxxxx.15053054001381505305457198",
"tbroker.workitem.sync_check.backend_total_value": 6995,
"tbroker.appversion": "1.1.135-180",
"#version": 1,
"beat": {
"hostname": "lixporta-p00",
"name": "lixporta-p00",
"version": "5.1.1"
In the action section, I can access the fields by using:
"actions": {
"my-logging-action": {
"logging": {
"text": "There are {{ctx.payload.hits.hits.0._source.....
After the source tag, I use for example the "type" field from the list above. Other example is:
"ctx.payload.hits.hits.0._source.beat.hostname"
This works pretty fine...
But it is not possible to use a field like
"tbroker.workitem.sync_check.tbroker_value"
The parser thinks that this fields are nested, but this is only a fieldname with dots in it.
Is there any possiblity to "escape" this fieldname?
Anyone who also have had this problem ?
Many thanks & best regards
Claus

I think the following should work:
{{#ctx.payload.hits.hits.0._source}}{{tbroker.workitem.sync_check.tbroker_value}}{{/ctx.payload.hits.hits.0._source}}
It is a limitation of Mustache and this is a workaround.
Another example may help - when in a context looping through hits (I have added // comments purely for clarity - they aren't valid Mustache syntax & should be removed):
{{#ctx.payload.hits.hits}}
// This works fine
{{_source.foo}}
// Not working if each hit's _source contains "bar.baz", not nested "bar">"baz"
{{_source.bar.baz}}
{{/ctx.payload.hits.hits}}
Applying the same workaround by adding an extra context/section:
{{#ctx.payload.hits.hits}}
// Put us in the context of [the current hit] > _source
{{#_source}}
// Now both of these work...
{{foo}}
// ...including this one containing a dot (yay!)
{{bar.baz}}
{{/_source}}
{{/ctx.payload.hits.hits}}

There is no way to directly access source fields that have dots in them, but if you apply a transform like this:
"transform": {
"script": {
"inline": "return [ 'host' : ctx.payload.hits.hits[0]._source.host, 'tbroker_value' : ctx.payload.hits.hits[0]._source['tbroker.workitem.sync_check.tbroker_value']]",
"lang": "painless"
}
}
and then you can use {{ctx.payload.host}} and {{ctx.payload.tbroker_value}} in your action.

Related

How to validate Sub-Sets of JSON Keys using match contains when there are nested JSON's in the response

From a response, I extracted a subset like this.
{
"base": {
"first": {
"code": "1",
"description": "Its First"
},
"second": {
"code": "2",
"description": "Its Second"
},
"default": {
"last": {
"code": "last",
"description": "No"
}
}
}
}
If I need to do a single validation using And match X contains to check
Inside first the Code is 1
Inside default-last the code is last?
Instead of using json path for every validation, I am trying to extract a specific portion and validate it. If there is no nested json paths, I can do it very easily using And match X contains, however when there are nested jsons, I am not able to do it.
Does this work for you:
* def first = get[0] response..first
* match first.code == '1'
* def last = get[0] response..default.last
* match last.code == 'last'
Edit: ok looks like you want to condense into one line as far as possible, more importantly to be able to do contains in nested nodes. Personally, I find this sometimes to be not worth the trouble, but here goes.
Refer also to these short-cuts: https://github.com/intuit/karate#contains-short-cuts
* def first = { code: "1" }
* match response.base.first contains first
* match response.base contains { first: '#(^first)' }
* def last = { code: 'last' }
* match response.base contains { first: '#(^first)', default: { last: '#(^last)' } }
Mhmm, My question is slightly different I think.
For example if I directly point to the first using a json path and save it to a variable savedResponse, I can do this validation
And match savedResponse contains {code: "1"}
If there were 10 Key value combinations under first and if I need to validate 6 of those, I can use the same json path and I can easily do it using match contains
Similiar way if I save the above response to a variable savedResponse, how I can validate mutliple things using match contains, in this. The below statement will not work anyway.
And match savedResponse contains {first:{code:"1"}, last:{code:"last"}}
However if I modify something will it work?

Retrieve json field value with importJSON

I have a problem with google spreadsheets. I try to import a value from a link (which returns me a JSON) but it seems like it does not work.
I tried this:
https://medium.com/#paulgambill/how-to-import-json-data-into-google-spreadsheets-in-less-than-5-minutes-a3fede1a014a#.pb26xo98x
The link returns a json like this:
{
"data": [
{
"time": "2016-10-16T07:00:00+0000",
"value": "249.884067074"
}
],
"summary": {
"name": "Custom Events",
"period": "daily",
"since": "2016-10-17T00:00:00+0000",
"until": "2016-10-17T00:00:00+0000"
}
}
How can I extract the value from the data field?
I tried like this:
=ImportJSON(myUrl, "/data[0]/value", "noInherit,noTruncate,rawHeaders")
According to a comment on the project page there is a fix that should be manually applied:
Chris says:
November 4, 2014 at 11:35 pm (UTC -4)
Trevor,
I was able to fix this problem by making a minor change to the
ParseData_ function. I changed line 286 in version 1.2.1 to:
if (i >= 0 && data[state.rowIndex]) {
and it seems to have addressed the issue.
Thank you!
CR

Collecting Data from Facebook posts using JPath / JSONPath

I have been at this for hours. How do you get filtering to work?
None of the solutions online works.
All I want to do is grab the comments(highlighted by these <<<>>>) from the json below from the name “Tori Smith”. I’ve been using this app to test http://jsonpath.curiousconcept.com/.
This is as far as I have gotten: ‘comments.data..from.id’
Data:
{
"id":"12029930209393029_10100748134340048",
"from":{
"id":"12029930209393029",
"name":"Tori Smith"
},
"message":"Buy this now",
"picture":"https:\/\/fbexternal-a.akamaihd.net\/app_full_proxy.php?app=141861192518680&v=1&size=z&cksum=a0471c1f5895cd22c74474fabc989c7e&src=http%3A%2F%2Fmedia3.policymic.com%2FYTM2OWUwN2Q0MSMvRnlpUTkxZU9DMWtGWFZ6TUNiYWh3RkxveXRjPS8yeDE6MTI4Nng2MjIvMTI4MHg2MjAvZmlsdGVyczpxdWFsaXR5KDcwKS9odHRwOi8vczMuYW1hem9uYXdzLmNvbS9wb2xpY3ltaWMtaW1hZ2VzL2JqNTdvbTZxZGd1N3ZpaGtvcWVrNnlzaTI5bW55dGZqanEwMWhuc3FqYjgxc3dkeGcyN2F6czV0eXV0bWJzZTguanBn.jpg",
"link":"http:\/\/mic.com\/articles\/101252\/this-tiny-box-will-let-you-stay-anonymous-on-the-internet",
"name":"This Tiny Box Will Let You Stay Anonymous on the Internet",
"caption":"Mic",
"description":"A simple and elegant solution to a major technology problem.",
"icon":"https:\/\/fbcdn-photos-d-a.akamaihd.net\/hphotos-ak-xpf1\/t39.2081-0\/10333103_752719651432828_1597152122_n.png",
"actions":[
{
"name":"Comment",
"link":"https:\/\/www.facebook.com\/12029930209393029\/posts\/10100748134340048"
},
{
"name":"Like",
"link":"https:\/\/www.facebook.com\/12029930209393029\/posts\/10100748134340048"
}
],
"privacy":{
"description":"Your friends",
"value":"ALL_FRIENDS",
"friends":"",
"networks":"",
"allow":"",
"deny":""
},
"type":"link",
"status_type":"app_created_story",
"application":{
"name":"Mic",
"namespace":"micmediaapp",
"id":"141861192518680"
},
"created_time":"2014-10-14T14:54:54+0000",
"updated_time":"2014-10-15T03:55:19+0000",
"comments":{
"data":[
{
"id":"10100748134340048_10100748984636048",
"from":{
"id":"123094958239849866",
"name":"Don Draper"
},
"message":"Even if I use Tor",
"can_remove":true,
"created_time":"2014-10-15T03:03:29+0000",
"like_count":0,
"user_likes":false
},
{
"id":"10100748134340048_10100749036726658",
"from":{
"id":"12029930209393029",
"name":"Tori Smith"
},
<<< "message":"Yes this can go with you and I think it works for all apps outside of TOR browser", >>>
"can_remove":true,
"created_time":"2014-10-15T03:55:19+0000",
"like_count":0,
"user_likes":false
},
{
"id":"10100748134340048_1010074901234658",
"from":{
"id":"12029930209393029",
"name":"Tori Smith"
},
<<< "message":"Second Text", >>>
"can_remove":true,
"created_time":"2014-10-15T03:55:19+0000",
"like_count":0,
"user_likes":false
}
],
"paging":{
"cursors":{
"after":"WTI5dGJXVnVkRjlqZFhKemIzSTZNVEF4TURBM05Ea3dNelkzTWpZMk5UZzZNVFF4TXpNME5UTXhPVG95",
"before":"WTI5dGJXVnVkRjlqZFhKemIzSTZNVEF4TURBM05EZzVPRFEyTXpZd05EZzZNVFF4TXpNME1qSXdPVG94"
}
}
}
}
To get at the comments you need to introduce a filter expression for filtering to comments by "Tori Smith" and then select the comment field.
Taking it step by step, to get all the comments, you need this:
$.comments.data
Then to filter to only the comments by "Tori Smith" add a filter like this:
$.comments.data[?(#.from.name == 'Tori Smith')]
Finally, to select only the message expand the query like this:
$.comments.data[?(#.from.name == 'Tori Smith')].message
I have tested this using the online JSON query tool here:
http://www.jsonquerytool.com/sample/jsonpathwhereselectcomments

How to add nested json object to Lucene Index

I need a little help regarding lucene index files, thought, maybe some of you guys can help me out.
I have json like this:
[
{
"Id": 4476,
"UrlName": null,
"PhoneData": [
{
"PhoneType": "O",
"PhoneNumber": "0065898",
},
{
"PhoneType": "F",
"PhoneNumber": "0065898",
}
],
"Contact": [],
"Services": [
{
"ServiceId": 10,
"ServiceGroup": 2
},
{
"ServiceId": 20,
"ServiceGroup": 1
}
],
}
]
Adding first two fields is relatively easy:
// add lucene fields mapped to db fields
doc.Add(new Field("Id", sampleData.Id.Value.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("UrlName", sampleData.UrlName.Value ?? "null" , Field.Store.YES, Field.Index.ANALYZED));
But how I can add PhoneData and Services to index so it can be connected to unique Id??
For indexing JSON objects I would go this way:
Store the whole value under a payload field, named for example $json. This field would be stored but not indexed.
For each (indexable) property (maybe nested) create an indexable field with its name as a XMLPath-like expression identifying the property, for example PhoneData.PhoneType
If is ok that all nested properties will be indexed then it's simple, just iterate over all of them generating this indexable field.
But if you don't want to index all of them (a more realistic case), how to know which property is indexable is another problem; in this case you could:
Accept from the client the path expressions of the index fields to be created when storing the document, or
Put JSON Schema into play to describe your data (assuming your JSON records have a common schema), and extend it with a custom property that would allow you to tag which properties are indexable.
I have created a library doing this (and much more) that maybe can help you.
You can check it at https://github.com/brutusin/flea-db

Using addToSet inside an array with MongoDB

I'm trying to track daily stats for an individual.
I'm having a hard time adding a new day inside "history" and can also use a pointer on updating "walkingSteps" as new data comes in.
My schema looks like:
{
"_id": {
"$oid": "50db246ce4b0fe4923f08e48"
},
"history": [
{
"_id": {
"$oid": "50db2316e4b0fe4923f08e12"
},
"date": {
"$date": "2012-12-24T15:26:15.321Z"
},
"walkingSteps": 10,
"goalStatus": 1
},
{
"_id": {
"$oid": "50db2316e4b0fe4923f08e13"
},
"date": {
"$date": "2012-12-25T15:26:15.321Z"
},
"walkingSteps": 5,
"goalStatus": 0
},
{
"_id": {
"$oid": "50db2316e4b0fe4923f08e14"
},
"date": {
"$date": "2012-12-26T15:26:15.321Z"
},
"walkingSteps": 8,
"goalStatus": 0
}
]
}
db.history.update( ? )
I've been browsing (and attempting) the mongodb documentation but they don't quite break it all the way down to dummies like myself... I couldn't quite translate their examples to my setup.
Thanks for any help.
E = noob trying to learn programming
Adding a day:
user = {_id: ObjectId("50db246ce4b0fe4923f08e48")}
day = {_id: ObjectId(), date: ISODate("2013-01-07"), walkingSteps:0, goalStatus: 0}
db.users.update(user, {$addToSet: {history:day}})
Updating walkingSteps:
user = ObjectId("50db246ce4b0fe4923f08e48")
day = ObjectId("50db2316e4b0fe4923f08e13") // second day in your example
query = {_id: user, 'history._id': day}
db.users.update(query, {$set: {"history.$.walkingSteps": 6}})
This uses the $ positional operator.
It might be easier to have a separate history collection though.
[Edit] On the separate collections:
Adding days grows the document in size and it might need to be relocated on the disk. This can lead to performance issues and fragmentation.
Deleting days won't shrink the document size on disk.
It makes querying easier/straightforward (e.g. searching for a period of time)
Even though #Justin Case puts the right answer he doesn't explain a few things in it extremely well.
You will notice first of all that he gets rid of the resolution on dates and moves their format to merely the date instead of date and time like so:
day = {_id: ObjectId(), date: ISODate("2013-01-07"), walkingSteps:0, goalStatus: 0}
This means that all your dates will have 00:00:00 for their time instead of the exact time you are using atm. This increases the ease of querying per day so you can do something like:
db.col.update(
{"_id": ObjectId("50db246ce4b0fe4923f08e48"),
"history.date": ISODate("2013-01-07")},
{$inc: {"history.$.walkingSteps":0}}
)
and other similar queries.
This also makes $addToSet actually enforce its rules, however since the data in this sub document could change, i.e. walkingSteps will increment $addToSet will not work well here anyway.
This is something I would change from the ticked answer. I would probably use $push or something else instead since $addToSet is heavier and won't really do anything useful here.
The reason for a separate history collection in my view would be what you said earlier with:
Yes, the amount of history items for that day.
So this array contains a set of days, which is fine but it sounds like the figure that you wish to get walkingSteps from, a set of history items, should be in another collection and you set walkingSteps according to the count of the amount of items in that other collection for today:
db.history_items.find({date: ISODate("2013-01-07")}).count();
Referring to MongoDB Manual, $ is the positional operator which identifies an element in an array field to update without explicitly specifying the position of the element in the array. The positional $ operator, when used with the update() method and acts as a placeholder for the first match of the update query selector.
So, if you issue a command to update your collection like this:
db.history.update(
{someCriterion: someValue },
{ $push: { "history":
{"_id": {
"$oid": "50db2316e4b0fe4923f08e12"
},
"date": {
"$date": "2012-12-24T15:26:15.321Z"
},
"walkingSteps": 10,
"goalStatus": 1
}
}
)
Mongodb might try to identify $oid and $date as some positional parameters. $ also is part of the atomic operators like $set and $push. So, it is better to avoid use this special character in Mongodb.