I'm trying to get a specific array item not by the array position, but by the content key.
Example JSON:
{"items": [{
"key": "prop-name",
"label": "Provider",
"type": "DROPDOWN",
"items": ["bla", "blub", "what", "ever"]
}, {
"key": "prop-modes",
"label": "Transport modes",
"type": "CHECKBOX",
"items": ["AIR", "RAIL", "ROAD", "SEA"]
}
]}
private static String URL_GLOBAL_FILTER = "/global-filter";
private static String PROP_NAME = "prop-name";
mvc.perform(get(URL_GLOBAL_FILTER).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.items", hasSize(10)))
.andExpect(jsonPath("$.items[?((#.key === \"" + PROP_NAME + "\" && #.type === \"DROPDOWN\"))]").exists())
.andExpect(jsonPath("$.items[0].items", hasSize(4)));
This works perfectly fine. But what I want to do is something like:
.andExpect(jsonPath("$.items[?(#.key == \"prop-name\")].items", containsString("bla")))
But that throws the following error:
java.lang.AssertionError: JSON path "$.items[?(#.key == "prop-name")].items"
Expected: a string containing "bla"
but: was a net.minidev.json.JSONArray (<[["bla","blub","what","ever"]]>)
What does the < > mean? How to access the array inside?
In jsonQueryTool it seems to be what I want.
(UPDATED question)
Have you tried using the hasItem matcher from Hamcrest?
import static org.hamcrest.Matchers.*;
.andExpect(jsonPath("$.items[?(#.key == 'prop-name')].items[*]", hasItem("bla")));
Related
I have the following terraform config:
resource "aws_dynamodb_table_item" "my_table" {
table_name = aws_dynamodb_table.my_table.name
hash_key = aws_dynamodb_table.my_table.hash_key
item = <<ITEM
{
"id": {"S": "nameAndCodes"},
"data": {"S": "[
{
"code": "03",
"displayName": "name1"
},
{
"code": "04",
"displayName": "name2"
}
]"}
}
ITEM
}
When the plan stage executes I receive the error:
Error: Invalid format of "item": Decoding failed: invalid character '\r' in string literal
The only way i can get this to work is to make the whole json a single line as follows:
"data": {"S": "[{\"code\": \"03\", \"displayName\": \"name1\"},{\"code\": \"04\", \"displayName\": \"name2\"}]"
This looks very ugly and difficult to manage.
Does anyone know how I can enter a multiline JSON inside a <<ITEM block?
To resolve that issue, You can use the jsonencode function to set the item value and put entire JSON object in there. Here is an example in Terraform from my project which creates a DynamoDB table and put an initial item.
resource "aws_dynamodb_table" "customer_table" {
name = "customer"
billing_mode = "PAY_PER_REQUEST"
hash_key = "customerId"
stream_enabled = false
attribute {
name = "customerId"
type = "S"
}
}
resource "aws_dynamodb_table_item" "customer_table_item" {
table_name = aws_dynamodb_table.customer_table.name
hash_key = aws_dynamodb_table.customer_table.hash_key
depends_on = [aws_dynamodb_table.customer_table]
item = jsonencode({
"customerId" : {
"S" : "1"
},
"firstName" : {
"S" : "John"
},
"lastName" : {
"S" : "Doe"
},
})
}
commands:
terrform init
terraform fmt
terraform plan
terraform apply
I'm getting a JSON object over the network, as a String. I'm then using Circe to parse it. I want to add a handful of fields to it, and then pass it on downstream.
Almost all of that works.
The problem is that my "adding" is really "overwriting". That's actually ok, as long as I add an empty object first. How can I add such an empty object?
So looking at the code below, I am overwriting "sometimes_empty:{}" and it works. But because sometimes_empty is not always empty, it results in some data loss. I'd like to add a field like: "custom:{}" and then ovewrite the value of custom with my existing code.
Two StackOverflow posts were helpful. One worked, but wasn't quite what I was looking for. The other I couldn't get to work.
1: Modifying a JSON array in Scala with circe
2: Adding field to a json using Circe
val js: String = """
{
"id": "19",
"type": "Party",
"field": {
"id": 1482,
"name": "Anne Party",
"url": "https"
},
"sometimes_empty": {
},
"bool": true,
"timestamp": "2018-12-18T11:39:18Z"
}
"""
val newJson = parse(js).toOption
.flatMap { doc =>
doc.hcursor
.downField("sometimes_empty")
.withFocus(_ =>
Json.fromFields(
Seq(
("myUrl", Json.fromString(myUrl)),
("valueZ", Json.fromString(valueZ)),
("valueQ", Json.fromString(valueQ)),
("balloons", Json.fromString(balloons))
)
)
)
.top
}
newJson match {
case Some(v) => return v.toString
case None => println("Failure!")
}
We need to do a couple of things. First, we need to zoom in on the specific property we want to update, if it doesn't exist, we'll create a new empty one. Then, we turn the zoomed in property in the form of a Json into JsonObject in order to be able to modify it using the +: method. Once we've done that, we need to take the updated property and re-introduce it in the original parsed JSON to get the complete result:
import io.circe.{Json, JsonObject, parser}
import io.circe.syntax._
object JsonTest {
def main(args: Array[String]): Unit = {
val js: String =
"""
|{
| "id": "19",
| "type": "Party",
| "field": {
| "id": 1482,
| "name": "Anne Party",
| "url": "https"
| },
| "bool": true,
| "timestamp": "2018-12-18T11:39:18Z"
|}
""".stripMargin
val maybeAppendedJson =
for {
json <- parser.parse(js).toOption
sometimesEmpty <- json.hcursor
.downField("sometimes_empty")
.focus
.orElse(Option(Json.fromJsonObject(JsonObject.empty)))
jsonObject <- json.asObject
emptyFieldJson <- sometimesEmpty.asObject
appendedField = emptyFieldJson.+:("added", Json.fromBoolean(true))
res = jsonObject.+:("sometimes_empty", appendedField.asJson)
} yield res
maybeAppendedJson.foreach(obj => println(obj.asJson.spaces2))
}
}
Yields:
{
"id" : "19",
"type" : "Party",
"field" : {
"id" : 1482,
"name" : "Anne Party",
"url" : "https"
},
"sometimes_empty" : {
"added" : true,
"someProperty" : true
},
"bool" : true,
"timestamp" : "2018-12-18T11:39:18Z"
}
I have the following JSON file. It is truncated for brevity of this question. An actual JSON file would contain 10 - 20 messages and 3 - 15 results.
{
"messages": [
{
"type": "msgInfo",
"description": "Some stuff happened"
},
{
"type": "msgInfo",
"description": "More stuff happened"
},
{
"type": "msgInfo",
"description": "yup, more stuff happened"
}
],
"results": [
{
"parameterId": "val_1",
"dataType": "Double",
"value": 123.45
},
{
"parameterId": "val_2",
"dataType": "Double",
"value": 246.80
},
{
"parameterId": "val_3",
"dataType": "Double",
"value": 135.79
},
{
"parameterId": "val_4",
"dataType": "Long",
"value": 20161021
}
]
}
I'm trying to retrieve the value of the value key based on the value of the parameterId key. For example, I need to return "123.45" using a JPath to "val_1".
So far I have this code (copied from this post) but I can't get the path correct.
JObject obj = JObject.Parse(json);
JToken token = obj["results"]["parameterId"];
Console.WriteLine(token.Path + " -> " + token.ToString());
Console.ReadLine();
What do I need to do in order to return "123.45" using a JPath to "val_1"?
To get the value token from one of the results in the results array based on the value of the parameterId token, you need to use the SelectToken method with a JSONPath query expression:
JToken token = obj.SelectToken("$.results[?(#.parameterId=='val_1')].value");
JSONPath syntax can be a little tricky to get right sometimes, depending on what you're trying to do, so you might find an online expression evaluator such as this one helpful to experiment with.
Alternatively, you can use a LINQ query to do the same thing:
JToken token = obj["results"]
.Where(result => (string)result["parameterId"] == "val_1")
.Select(result => result["value"])
.FirstOrDefault();
Here is a fiddle showing both approaches: https://dotnetfiddle.net/8qiSCa
I am writing my first api (express/node) and one of the endpoints receives json data in the body like:
{
"text": "some comment here...",
"tags": [
{"id": 0, "tag": "some tag 1"},
{"id": 123, "tag": "some tag 2"}
],
"date": "1452305028289",
}
Is there some way you can check that all the properties exist on the object and that they have values? Or do you have to write a custom function checking for each required property and values?
You can use one of these packages for validating data with NodeJS:
https://github.com/hapijs/joi
https://github.com/mafintosh/is-my-json-valid
https://github.com/ctavan/express-validator
A simple solution would be this function that takes an object and a list of strings as the properties of that object:
var checkProperties = function (obj, props) {
return props
.map(function(prop) { return obj.hasOwnProperty(prop); })
.reduce(function (p, q) { return p && q; });
}
use like this
checkProperties({ prop1: someValue, prop2: someOtherValue }, ["prop1", "prop2"]); // true
I had a object array containing items
"0: Object
Entity: "Customer"
Id: 157
Message: "testMessage1"
Property: Object
Name: "LastName"
Rules: "NotEmpty""
Here, How could I pass Name value to Property
Name is act as key within in Property object.
how could I Discard the Name and assign the value of Name i.e. (Last Name) to Property
This is what I have right now:
[
{
"Entity":"Customer",
"Property": {"Name": "Email", "Type": "System.String" },
"Rules":"NotEmpty",
"Message":"ssdsdsds",
"Id":157,
"ValueToCompare": null,
}
]
Here, I need to assign Name value (i.e : Email) to Property Directly (it would be like this :-- "Property": "Email")
assuming this is your json
[
{
"0": {
"Entity": "Customer",
"Id": 157,
"Message": "testMessage1"
},
"Property": {
"Name": "LastName",
"Rules": "NotEmpty"
}
}
]
your original json contain in
originaljson
and transform json contain in
transformjson
JSONArray originaljson;
JSONArray transformjson=originaljson;
for(int i=0;i<originaljson.length();i++)
{
JSONObject mainJson=originaljson.getJSONObject(i);
String name=mainJson.getJSONObject("Property").getString("Name");
//mainJson.remove("Property");
JSONObject mainJsonTransform=transformjson.getJSONObject(i);
mainJsonTransform.remove("Property");
mainJsonTransform.put("Property",name);
}
now your transformjson contain the desired json
Thank you guys for your interest with this question.
At last I have write down the proper solution
My own solution to solve this problem is..
In javascript :
function addProp(obj, propName) {
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
if (p == propName) {
if (obj[p].Name == null) {
obj[p] = obj[p];
}
else
{
obj[p] = obj[p].Name;
}
} else if (typeof obj[p] == 'object') {
addProp(obj[p], propName);
}
}
}
return obj;
}
Calling this function :
addProp(data, 'Property')
This work properly now