I need to collect an entity records as from date to date, based on one attribute's value. If the value of type attribute is sequentially same based on date, it should be grouped by date. Since date mentioned as sequentially, should be ordered. Even if the value of type attribute of a record is different, rest of the records also should be under the same day. See the visual representation. I've tried this;
Map<LocalDate, List<Entity>> collection = entities.stream().collect(Collectors.groupingBy(Entity::getDate))
.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
In my implementation, I am able to only collect by dates, but I want to collect by DateRange. I want to achieve some thing like this;
Map<DateRange, List<Entity>> collection = entities.stream()...// implementation
Entity
[
{
"id": 1,
"date": "2020-01-01",
"type": 5
},
{
"id": 2,
"date": "2020-01-01",
"type": 5
},
{
"id": 1,
"date": "2020-01-02",
"type": 5
},
{
"id": 2,
"date": "2020-01-02",
"type": 5
},
.
.
.
]
Example
Date range changes based on the value of the type attribute. For example, if type=5 for all dates, so all records should be in one range. Let's say there are only records for one year and I'm assuming there are only two unique id value(id=1, id=2), so in collection I should achieve this;
[{
"From: 2020-01-01, To: 2020-12-31": [{
"record1":
{
"id": 1,
"type": "5"
},
"record2":
{
"id": 2,
"type": "5"
}
}]
}]
Another example
If the type=5 for all dates except '2020-02-01' and in '2020-02-01' type=6 for the id=1, then ranges should be like the below. I'm still assuming, there are records only for one year and there are only two unique id value(id=1, id=2).
[
{
"From: 2020-01-01, To: 2020-01-31": [{
"record1":
{
"id": 1,
"type": "5"
},
"record2":
{
"id": 2,
"type": "5"
}
}],
},
{
"From: 2020-02-01, To: 2020-02-01": [{
"record1":
{
"id": 1,
"type": "6"
},
"record2":
{
"id": 2,
"type": "5"
}
}],
},
{
"From: 2020-02-02, To: 2020-12-31": [{
"record1":
{
"id": 1,
"type": "5"
},
"record2":
{
"id": 2,
"type": "5"
}
}]
}
]
Related
I am trying to get the id of the OutterObject where the InnerObject id is a specific value and the date is the most recent of all InnerObject of all OutterObject.
I'm trying to achieve that with streams.
Searching for id "ab", it should return "def"
here is a json example of the structre.
{
"OutterObject": [
{
"id": "abc",
"InnerObject": [
{
"id": "ab",
"date": "1"
},
{
"id": "de",
"date": "2"
},
{
"id": "ab",
"date": "3"
}
]
},
{
"id": "def",
"InnerObject": [
{
"id": "ab",
"date": "9"
},
{
"id": "de",
"date": "3"
},
{
"id": "ab",
"date": "1"
}
]
}
]
}
Use flatMap to gather all objects in the same array :
OutterObject.stream().flatMap(outer -> outer.getInnerObject().stream());
Use max() and Comparator to get the higher value
Combine both to get something like :
Optional<Date> maxDate = OutterObject.stream().flatMap(outer -> outer.getInnerObject().stream()).max(Comparator.comparing(InnerObject::getDate));
This is solved with :
Optional<SimpleImmutableEntry<String, InnerObject>> mostRecentOutterObjectId= MasterObject.getOutter().stream()
.flatMap(outter-> outter.getInner().stream()
.map(inner-> new SimpleImmutableEntry<String, InnerObject>(outter.getId(), inner)))
.filter(outterMap-> StringUtils.equals(outterMap.getValue().getId(), "ab")))
.max((innerA,innerB) -> innerA.getValue().getDate().compareTo(innerB.getValue().getDate()));
I am open to improvement if you see some.
I am using jsonpath to filter.
Json(Dummy json just to explain) source String, which is basically a list of Operating systems and details of its programs etc. In this example, the OS whose id = 1403 is a windows 10 OS and has 2 features acchritecture and browser. There are more details to the browser feature as shown in json
[
{
"id": 1403,
"os": "window 10",
"features": [
{
"id": 1356,
"name": "architecture",
"value": [
{
"id": 1308,
"feature": [
{
"id": 1262,
"key": "name",
"value": "amd64"
}
]
}
],
"category": "cat1"
},
{
"id": 1357,
"name": "browser",
"value": [
{
"id": 1309,
"feature": [
{
"id": 1263,
"key": "name",
"value": "Firefox"
},
{
"id": 1265,
"key": "version",
"value": "187"
}
]
}
],
"category": "cat2"
}
]
},
{
"id": 2804,
"os": "window 7",
"features": [
{
"id": 2764,
"name": "architecture",
"value": [
{
"id": 2719,
"feature": [
{
"id": 2679,
"key": "name",
"value": "amd64"
}
]
}
],
"category": "cat1"
},
{
"id": 2765,
"name": "browser",
"value": [
{
"id": 2722,
"feature": [
{
"id": 2685,
"key": "name",
"value": "Chrome"
},
{
"id": 2684,
"key": "version",
"value": "87.0.4280.88"
}
]
}
],
"category": "cat2"
}
]
}
]
I want to be able to filter the json such that
features[*].name == 'browser' and features[*].value[*].feature[*].value == 'chrome'
What will be the JsonPath string that can help me achieve above query? The above query uses similar syntax used by JsonPath string but doesn't do the job. Its just to explain.
There is another example here gets Movie Title Given 'Starring' field
And would like to get the full OS json that fulfils this condition. In this case a array of OS which contains only one OS i.e. with id= 2804
[
{
"id": "2804",
...
}
]
I am stuck much before what aim to achieve. Here is my code to get all the OS that have "name=browser". I get the array but it only contains value[] items. I want it get the full json. It returns object with IDs- 1357, 2765.
List<Map<String, Object>> expensive = JsonPath.parse(jsonDataSourceString)
.read("$[*].features[*].[?(#.name == 'browser')]");
To get the outer array you need to use the filter like $[?(...)]
For your current use case, we need to use nested array filters. There is an open issue in JsonPath for filter on children level. (Refer here).
Luckily, there is a workaround suggested to use contains over here.
we can use the below expression to filter:
List<Object> expensive = JsonPath.parse(jsonDataSourceString)
.read("$[?(#.features[?(#.name == 'browser')].value[*].feature[*].value contains 'Chrome')]");
Prints the below output
{id=2804, os=window 7, features=[{"id":2764,"name":"architecture","value":[{"id":2719,"feature":[{"id":2679,"key":"name","value":"amd64"}]}],"category":"cat1"},{"id":2765,"name":"browser","value":[{"id":2722,"feature":[{"id":2685,"key":"name","value":"Chrome"},{"id":2684,"key":"version","value":"87.0.4280.88"}]}],"category":"cat2"}]}
I have a json response something like this:
"results": [
{
"id": "1",
"name": "YYY",
"shortName": "Y"
},
{
"id": "2",
"name": "XXX",
"shortName": "X"
},
{
"id": "3",
"name": "ZZZ",
"shortName": "Z"
}
]
I want to get id value when I send name value. For example if name = ZZZ return me id value in this case 3 using rest assured
Json path json-path-2.9.0 with rest-assured
import static com.jayway.restassured.path.json.JsonPath.from;
below JsonPath query
from(response).getList("results.findAll { it.name=='ZZZ' }.id").toString() //returns 3
from(response).getList("results.findAll { it.name=='XXX' }.id").toString() //returns 2
I have a JSONArray within a JSONArray, I want to apply JSONPath expression on this in such a way that i get JSONObject or JSONArray as a result when a condition is satsified on the inner JSONArray.
Eg:
{
"A": [
{
"B": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
}
],
"C": {
"id": 10,
"name": "PQR"
},
"id": 25,
"name": "XYZ"
},
{
"B": [
{
"id": 4
},
{
"id": 5
},
{
"id": 6
}
],
"C": {
"id": 15,
"name": "PQR"
},
"id": 20,
"name": "XYZ"
}
]
}
if i want all elements of A where C.id = 10, I would use: $.A[?(#.C.id == 10)]
Now, What predicate is to be used to obtain all the objects within A, where B.id = 1? Note: B is an array of JSON objects.
I had success with $.A[?(#.B[?(#.id == 1)])]
but only when using Scala's Gatling implementation:
http://jsonpath.herokuapp.com/
The Jayway implementation seems to totally ignore the inner filter and according to an issue on their GitHub, that's a bug.
[
{
"_class": "com.netas.netmetriks.common.model.entity.WorkOrder",
"failCount": 0,
"id": "1",
"messageType": "RESET_DCU",
"ongoingWorks": [
1
],
"status": "IN_PROGRESS",
"successCount": 0,
"type": "workorder",
"workOrderDetailMap": {
"1": {
"data": {
"_class": "com.netas.netmetriks.common.model.converted.DeviceId",
"manufacturerFlag": "DSM",
"serialNumber": "87654321"
},
"dcuId": {
"manufacturerFlag": "DSM",
"serialNumber": "87654321"
},
"id": 1,
"requestDate": "20160818114933",
"resultDocuments": [],
"status": "IN_PROGRESS"
},
"2": {
"data": {
"_class": "com.netas.netmetriks.common.model.converted.DeviceId",
"manufacturerFlag": "DSM",
"serialNumber": "87654322"
},
"dcuId": {
"manufacturerFlag": "DSM",
"serialNumber": "87654322"
},
"id": 2,
"requestDate": "20160818114934",
"resultDocuments": [],
"status": "IN_PROGRESS"
}
}
}
]
Simply i want to obtain inner of "1" and "2" objects.
I am trying to obtain data,dcuId,id,requestDate,resultDocuments,status.
SELECT wd.* FROM netmetriks n
UNNEST workOrderDetailMap wd
WHERE n.type = 'workorder' and n.id = '1' ORDER BY n.documentId ASC LIMIT 10 OFFSET 0
I wrote a query but could not get rid of "1" and "2".
HashMap is used in entity when storing data so the result shows 1,2,3,4 so on...