Using JSONPath get only 2 key-value pair when a condition is met - filter

With the following json object.
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
Using JSONPath. Is there any expression that can get only the key-value pair "author" and "title" for all books costing less that 13.00. The result will be something like:
[{
"author": "Nigel Rees",
"title": "Sayings of the Century"
}, {
"author": "Evelyn Waugh",
"title": "Sword of Honour"
}, {
"author": "Herman Melville",
"title": "Moby Dick"
}
]
I started with $.store.book[?(#.price < 13)] but this gets all the elements on each book costing less than 13.00. Not the desired behavior. Any help is much appreciated.

You are close; this expression:
$.store.book[?(#.price < 13)]["author","title"]
or, depending on the implementation
$.store.book[?(#.price < 13)][]author,title
should get you
[
{
"author" : "Nigel Rees",
"title" : "Sayings of the Century"
},
{
"author" : "Evelyn Waugh",
"title" : "Sword of Honour"
},
{
"author" : "Herman Melville",
"title" : "Moby Dick"
}
]
or
[
"Nigel Rees",
"Sayings of the Century",
"Evelyn Waugh",
"Sword of Honour",
"Herman Melville",
"Moby Dick"
]

Related

Elastic search query - all objects of nested array should have specific value

I want to write Elasticsearch query where I am able to look into a nested array, and check a key for all those elements inside the array, if all of them have that value then the root document should be selected.
this is a sample data :
[
{
"_index": "allproperties",
"_type": "_doc",
"_id": "5241050",
"_score": 0.0,
"_source": {
"id": 5241050,
"type": "HOUSE",
"state": "NSW",
"agency": {
"id": 31,
"code": "AU_LNT",
"name": "Luthor Properties",
"config": "{}"
},
"branch": {
"id": 89,
"name": "Luthor Sales Unit Trust",
"tradingName": "Luthor Properties",
"internalCode": "AU_LNT_G"
},
"images": null,
"leases": [
{
"id": 26439,
"bond": 2000,
"leased": true,
"source": "PORTAL",
"status": "SIGNED",
"endDate": "2022-11-06T00:00:00",
"tenants": [
{
"id": 11106,
"role": "TENANT",
"user": {
"id": 38817,
"dob": "1900-01-01",
"name": "Liam",
"email": "tempo#tempo.com",
"phone": "+61400000000",
"surname": "Tempo",
"salutation": "Mr.",
"invitations": null,
"lastInAppActivity": null
},
"address": "45675 Bruce Hwy, Coolbie QLD 4850, Australia",
"extendedData": "{\"rentSplitAmount\":22.62}",
"roleAdjective": "PRIMARY",
"addressComponents": {
"state": "QLD",
"suburb": "Coolbie",
"country": "Australia",
"postcode": "4850",
"streetName": "Bruce Hwy",
"unitNumber": null,
"poboxNumber": null,
"streetNumber": "45675",
"addressComponentsUnavailable": null
}
}
],
"signDate": "2022-10-05T04:58:08.887",
"startDate": "2022-10-06T00:00:00",
"moveInDate": "2022-10-06T00:00:00",
"appointments": [
{
"id": 3506,
"type": "REMOTE",
"date_time": "2022-10-12T04:56:00+00:00",
"createdBy": "Lex Luthor",
"createdDate": "2022-10-05T04:56:52.936",
"lastModifiedBy": "Lex Luthor",
"lastModifiedDate": "2022-10-05T04:56:53.51"
}
],
"createdDate": "2022-10-05T04:55:42.247",
"rentalAmount": 500,
"dateAvailable": null,
"extendedData": {
"last_rent_adjustment_date": 1665014400000
},
"leaseDuration": 32,
"rentalFrequency": "2",
"signedManually": false
}
],
"refId": "b66326eb-a6b2-42b6-b058-b46847e13399",
"source": "PT",
"status": null,
"suburb": "Hurstville",
"address": "456 Forest Road Hurstville NSW AUSTRALIA 2220",
"country": "Australia",
"bedrooms": 3,
"category": null,
"pmsCode": "84c34d15-a0ab-4791-b9e3-1bdac215b99c",
"postcode": "2220",
"agencyId": 31,
"bathrooms": 3,
"branchId": 89,
"carspaces": 3,
"createdBy": "system",
"streetname": "Forest Road",
"unitnumber": null,
"description": null,
"createdDate": "2022-10-05T04:51:12.619",
"entitlements": [
{
"id": 3453799,
"role": "LANDLORD",
"user": {
"id": 22855,
"dob": null,
"name": "please enter ownership name",
"email": "mag.m#rr.com.au",
"phone": "0400000000",
"surname": "",
"salutation": null,
"lastInAppActivity": null
},
"company": {
"id": 137,
"abn": "",
"acn": "",
"phone": "0400000000",
"address": "1234 Park Avenue New York NY USA 10037-1702",
"companyName": "please enter ownership name",
"displayName": "please enter ownership name",
"email": "mag.m#rr.com.au"
},
"roleAdjective": "GROUP"
},
{
"id": 3453800,
"role": "AGENT",
"user": {
"id": 20054,
"dob": null,
"name": "Paul",
"email": "p.b#mr.com",
"phone": "+61403084232",
"surname": "Botti",
"salutation": null,
"lastInAppActivity": null
},
"company": null,
"roleAdjective": "MANAGING"
},
{
"id": 3453801,
"role": "AGENT",
"user": {
"id": 20054,
"dob": null,
"name": "Paul",
"email": "p.b#mr.com",
"phone": "+61403084232",
"surname": "Botti",
"salutation": null,
"lastInAppActivity": null
},
"company": null,
"roleAdjective": "LEASING"
}
],
"streetnumber": "456",
"advertised": false,
"commission_type": null,
"lastModifiedBy": "system",
"lastModifiedDate": "2022-10-05T04:58:09.043",
"_meta": {
"branches": {
"id": [
89
]
},
"agencies": {
"id": [
31
]
},
"user_property_entitlement": {
"id": [
3453799,
3453800,
3453801
]
},
"users": {
"id": [
20054,
22855,
38817
]
},
"companies": {
"id": [
137
]
},
"leases": {
"id": [
26439
]
},
"user_lease_entitlement": {
"id": [
11106
]
},
"appointments": {
"id": [
3506
]
}
}
},
"sort": [
1664945472619,
0.0
]
}
]
In this particular case, leases is a nested document, I want to select the documents where all the leases are in cancelled state or leases is null, i.e; either all of the objects inside leases should have status as CANCELLED or the leases key should be null.
Already went through this question, but did'nt quite get it as its an old answer from 2015 and methods used in this got deprecated.
Try this query:
GET idx_test/_search?filter_path=hits.hits
{
"query": {
"bool": {
"must_not": [
{
"nested": {
"path": "leases",
"query": {
"bool": {
"must_not": [
{
"bool": {
"should": [
{
"term": {
"leases.status.keyword": "CANCELLED"
}
},
{
"bool": {
"must_not": [
{
"exists": {
"field": "leases"
}
}
]
}
}
]
}
}
]
}
}
}
}
]
}
}
}

Bind an Array with dynamic length to an Adaptive Card

I was wondering how I could bind an array which can have a dynamic length to an element in Microsofts Adaptive Cards. Specifically, I want to make a list with instructions and display those in "kind-of-a-list" with a dynamic layout. In a perfect world, ths list would be filled dynamically and adjust its length to the length of the array. Any ideas/workarounds?
Card Payload:
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.2",
"body": [
{
"type": "TextBlock",
"text": "${title}",
"size": "Medium",
"weight": "Bolder",
"wrap": true,
"separator": true
},
{
"type": "FactSet",
"facts": [
{
"title": "1.",
"value": "${instructions[1]}"
},
{
"title": "2.",
"value": "${instructions[2]}"
},
{
"title": "3.",
"value": "${instructions[3]}"
},
{
"title": "4.",
"value": "${instructions[4]}"
},
{
"title": "5.",
"value": "${instructions[5]}"
}
],
"isVisible": false,
"$data": "${$root['instructions[0]']}",
"separator": true
}
]
}
Card Data:
{
"title": "Instructions:",
"instructions" : [
"blablablba",
"qwerertzasdfadfds fasdf ",
"asdfkjhasf 3 asdflkjw",
"Lorem ipsum dolor mi",
"hello world",
"last instruction"
]
}
the best way to do this is if you change your JSON a litle bit:
{
"title": "Instructions:",
"instructions": [{
"id": "1",
"text": "blablablabla"
},
{
"id": "2",
"text": "qwerertzasdfadfds fasdf "
},
{
"id": "2",
"text": "asdfkjhasf 3 asdflkjw"
},
{
"id": "3",
"text": "Lorem ipsum dolor mi"
},
{
"id": "4",
"text": "hello world"
},
{
"id": "5",
"text": "last instruction"
}
]
}
This way you can build the card like this:
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.3",
"body": [
{
"type": "TextBlock",
"text": "${title}",
"size": "Medium",
"weight": "Bolder",
"wrap": true,
"separator": true
},
{
"type": "FactSet",
"facts": [
{
"$data": "${instructions}",
"title": "${id}.",
"value": "${text}"
}
],
"separator": true
}
]
}
Which would look like this:

parse nested hash into RUBY to print output, without taking duplicate values

I have a nested hash and I am able to iterate it and print the section and the field values from the hash. I'm trying to iterate over this nested hash to create a steps guide, I want to create a file with the information and the output file to have the output written like:
steps_guide [section]elemento1 [section]elemento2 [section]elemento3
steps_guide [section]elemento2 [section]elemento3 [section]elemento4
....
steps_guide [section]radio [section]xenon [section]aluminio
steps_guide [section]xenon [section]aluminio [section]boro
If a section name is duplicated in other elementos I only need to print something like:
steps_guide expected_[section_duplicated]elemento1 [section]elemento2 [section]elemento3
and not print that section again and print the next element, and this for all the nested hash. Here is the source data.
_Data =[
{
"name": "script",
"elements": [
{
"name": "unknown group",
"headers": {
"map": {}
},
"agent": "",
"bottom_comments": [],
"checks": [
{
"title": "",
"field": "elemento1",
"section": "control_psd",
"value": "0",
},
{
"title": "",
"field": "elemento2",
"section": "control_psd",
"value": "0",
},
{
"title": "",
"field": "elemento3",
"section": "control_ptt",
"value": "0",
},
{
"title": "",
"field": "elemento4",
"section": "control_save",
"value": "0",
},
{
"title": "",
"section": "control_relay",
"field": "elemento5",
"value": "0",
},
{
"title": "",
"section": "control_relay",
"field": "elemento6",
"value": "1",
},
{
"title": "",
"section": "control_reply",
"field": "elemento7",
"value": "1",
},
{
"title": "",
"section": "plc_status",
"field": "elemento8",
"value": "1",
},
{
"title": "",
"section": "plc_status",
"field": "elemento9",
"value": "1",
},
{
"title": "",
"section": "plc_value",
"field": "elemento10",
"value": "0",
},
{
"type": "condiciones",
"elementos": [
{
"table": [
{
"title": "",
"section": "regresion",
"name": "radio",
},
{
"title": "",
"section": "regresion",
"name": "xenon",
},
{
"title": "",
"section": "update",
"name": "aluminio",
},
{
"title": "",
"section": "cont",
"name": "boro",
},
{
"title": "",
"section": "container",
"name": "oro",
},
{
"title": "",
"section": "after",
"name": "bromo",
},
{
"title": "",
"section": "after",
"name": "oxigeno",
}
]
}
]
}
]
}
]
}
]

elasticsearch get specific fields

I am trying to search data from following indexed data
PUT /nested_test100/t/1
{
"title": "Nest eggs1",
"body": "Making your money work...",
"tags": [ "cash1", "shares1" ],
"comments": [
{
"name": "John Smith1",
"comment": "Great article1",
"age": 28,
"stars": 1,
"date": "2014-09-01"
},
{
"name": "Alice White1",
"comment": "More like this please1",
"age": 31,
"stars": 1,
"date": "2014-10-22"
}
]
}
PUT /nested_test100/t/2
{
"title": "Nest eggs2",
"body": "Making your money work...",
"tags": [ "cash", "shares" ],
"comments": [
{
"name": "John Smith2",
"comment": "Great article2",
"age": 30,
"stars": 2,
"date": "2014-09-01"
},
{
"name": "Alice White2",
"comment": "More like this please2",
"age": 31,
"stars": 2,
"date": "2014-10-22"
}
]
}
PUT /nested_test100/t/3
{
"title": "Nest eggs3",
"body": "Making your money work...",
"tags": [ "cash3", "shares3" ],
"comments": [
{
"name": "John Smith3",
"comment": "Great article3",
"age": 28,
"stars": 3,
"date": "2014-09-01"
},
{
"name": "Alice White3",
"comment": "More like this please3",
"age": 30,
"stars": 3,
"date": "2014-10-22"
}
]
}
GET /nested_test100/t/_search
what I want is to get title, body tags only and only comments having age=28.
How I should write query dsl for that.
what I have written is following
POST /nested_test100/t/_search
{
"fields" : ["title","comments.age","body","tags"],
"query" : {
"term" : { "comments.age" : "28" }
}
}
and its giving me data like this
"hits": [
{
"_index": "nested_test100",
"_type": "t",
"_id": "1",
"_score": 1,
"fields": {
"comments.age": [
28,
31
],
"title": [
"Nest eggs1"
],
"body": [
"Making your money work..."
],
"tags": [
"cash1",
"shares1"
]
}
},
{
"_index": "nested_test100",
"_type": "t",
"_id": "3",
"_score": 1,
"fields": {
"comments.age": [
28,
30
],
"title": [
"Nest eggs3"
],
"body": [
"Making your money work..."
],
"tags": [
"cash3",
"shares3"
]
}
}
]
but I don't want comments having age other than 28.
I am using elasticsearch version 1.7
Please use inner_hits to include nested inner objects as inner hits to a search hit.
The search request would be like :
POST test/_search
{
"query": {
"nested": {
"path": "comments",
"query": {
"match": {"comments.age" : 28}
},
"inner_hits": {}
}
}
}
P.S : You will need to map the comments as a nested field (as already mentioned by Val)

REQL to match string expression

I have the following json:
{
"release": {
"genres": {
"genre": "Electronic"
},
"identifiers": {
"identifier": [
{
"description": "Text",
"value": "5 709498 101026",
"type": "Barcode"
},
{
"description": "String",
"value": 5709498101026,
"type": "Barcode"
}
]
},
"status": "Accepted",
"videos": {
"video": [
{
"title": "Future 3 - Renaldo",
"duration": 446,
"description": "Future 3 - Renaldo",
"src": "http://www.youtube.com/watch?v=hpc9aQpnUjc",
"embed": true
},
{
"title": "Future 3 - Silver M from album We are the Future / 1995 Denmark / Archivos de Kraftwerkmusik",
"duration": 461,
"description": "Future 3 - Silver M from album We are the Future / 1995 Denmark / Archivos de Kraftwerkmusik",
"src": "http://www.youtube.com/watch?v=nlcHRI8iV4g",
"embed": true
},
{
"title": "Future 3 - Bubbles At Dawn",
"duration": 710,
"description": "Future 3 - Bubbles At Dawn",
"src": "http://www.youtube.com/watch?v=ABBCyvGMOFw",
"embed": true
}
]
},
"labels": {
"label": {
"catno": "APR 010CD",
"name": "April Records"
}
},
"companies": {
"company": {
"id": 26184,
"catno": "",
"name": "Voices Of Wonder",
"entity_type_name": "Published By",
"resource_url": "http://api.discogs.com/labels/26184",
"entity_type": 21
}
},
"styles": {
"style": [
"Abstract",
"IDM",
"Downtempo"
]
},
"formats": {
"format": {
"text": "",
"name": "CD",
"qty": 1,
"descriptions": {
"description": "Album"
}
}
},
"country": "Denmark",
"id": 5375,
"released": "1995-00-00",
"artists": {
"artist": {
"id": 5139,
"anv": "",
"name": "Future 3",
"role": "",
"tracks": "",
"join": ""
}
},
"title": "We Are The Future 3",
"master_id": 638422,
"tracklist": {
"track": [
{
"position": 1,
"duration": "8:04",
"title": "Future 3"
},
{
"position": 2,
"duration": "7:38",
"title": "Silver M"
},
{
"position": 3,
"duration": "7:27",
"title": "Renaldo"
},
{
"position": 4,
"duration": "6:04",
"title": "B.O.Y.D."
},
{
"position": 5,
"duration": "6:12",
"title": "Fumble"
},
{
"position": 6,
"duration": "6:12",
"title": "Dawn"
},
{
"position": 7,
"duration": "11:54",
"title": "Bubbles At Dawn"
},
{
"position": 8,
"duration": "6:03",
"title": "D.A.W.N. At 6"
},
{
"position": 9,
"duration": "8:50",
"title": 4684351684651
}
]
},
"data_quality": "Needs Vote",
"extraartists": {
"artist": [
{
"id": 2647642,
"anv": "",
"name": "Danesadwork",
"role": "Cover",
"tracks": "",
"join": ""
},
{
"id": 2647647,
"anv": "",
"name": "Djon Edvard Petersen",
"role": "Photography By",
"tracks": "",
"join": ""
},
{
"id": 114164,
"anv": "",
"name": "Anders Remmer",
"role": "Written-By",
"tracks": "",
"join": ""
},
{
"id": 435979,
"anv": "",
"name": "Jesper Skaaning",
"role": "Written-By",
"tracks": "",
"join": ""
},
{
"id": 15691,
"anv": "",
"name": "Thomas Knak",
"role": "Written-By",
"tracks": "",
"join": ""
}
]
},
"notes": "© 1995 April Records APS ℗ 1995 April Records APS"
}
}
I am trying to get those titles which end with 'At Dawn'.
I am using the following command
r.db("discogs1").table("releases").filter(function(doc){ return doc('release')('title').match('At Dawn$')})
But I get errors as follows:
RqlRuntimeError: Expected type STRING but found NUMBER in:r.db("discogs1").table("releases").filter(function(var_24) { return var_24("release")("title").match("At Dawn$"); })
I tried different combinations but I can't seem to get it to work
It seems that some of your documents don't have a row('release')('title') property that is a string. Some of them are numbers, so when you try to call .match on them, they throw an error because .match only works on strings.
To see if this is true, try the following:
r.db("discogs1").table("releases")
.filter(r.row('release')('title').typeOf().ne('STRING'))
.count()
Ideally, the result of this should be 0, since no document should have a title property that's not a string. If it's higher than 0, that's why you're getting an error.
If you want to only get documents where the title is a string, you can do the following:
r.db("discogs1").table("releases")
.filter(r.row('release')('title').typeOf().eq('STRING'))
.filter(function(doc){ return doc('release')('title').match('At Dawn$')})
This query will work, because it will filter our all documents where the title is not a string.
If you want to coerce all title into strings, you can do the following:
r.db("discogs1").table("releases")
.filter(r.row('release')('title').typeOf().ne('STRING'))
.merge(function (row) {
return {
'title': row('title').coerceTo('string')
}
})
If you want to delete all documents where the title is not a string, you can do this:
r.db("discogs1").table("releases")
.filter(r.row('release')('title').typeOf().ne('STRING'))
.delete()

Resources