javajava-8java-stream

Get count of matching JSON keys using the Java Stream API


I have a JSON object that looks like this:

[
    {
        "startAt": 1617605301292,
        "endAt": 1617605317095,
        "duration": 15803,
        "selection": {
            "selected.Speed": "0",
            "selected.Low": "65535",
            "selected.Fast": "7173",
            "selected.medium": "5"
        },
        "details": {
            "phase": [{
                "value": "2",
                "timestamp": 1617605301316
            }]
        }
    },
    {
        "startAt": 1617603849697,
        "endAt": 1617603966378,
        "duration": 116681,
        "selection": {
            "selected.Speed": "0",
            "selected.Low": "65535",
            "selected.Fast": "123",
            "selected.medium": "5"
        },
        "details": {
            "phase": [{
                "value": "2",
                "timestamp": 1617603849749
            }]
        }
    }
]

I need to count how many times selected.Fast has occurred. I am trying with stream and this is what I have written so far:

List<Map<String, Object>> jsonObj = mapper.readValue(jArr, new TypeReference<List<Map<String, Object>>>(){});
                
Map<String, Long> counted = jsonObj.stream()
        .map(x -> x.get("selection").toString() )
        .collect(Collectors.toList())
        .stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

System.out.println(counted.toString());

But I am getting count of all the key inside selection object, and I want count for specific JSON key which is selected.Fast.

For example:

selected.Fast:"7173" -> occurred 5 times 
selected.Fast:"123"  -> occurred 2 times

Any help would be appreciated.


Solution

  • Can you check if this is what you are looking for ?

     List<JsonNode> jsonObj = mapper.readValue(jArr, new TypeReference<List<JsonNode>>() {
        });
    
        Map<String, Long> counted = jsonObj.stream()
                .map(x -> {
                    String selection = x.get("selection").get("selected.Fast").asText();
                    return "selected.Fast:" + selection;
                }).collect(Collectors.toList())
                .stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    
        System.out.println(counted); //{selected.Fast:123=1, selected.Fast:7173=1}
    

    Edit: Without converting to JsonNode

        List<Map<String, Object>> jsonObj = mapper.readValue(jArr, new TypeReference<List<Map<String, Object>>>(){});
    
        Map<String, Long> counted = jsonObj.stream()
                .map(x -> {
                    String selection = ((Map<String,Object>)x.get("selection")).get("selected.Fast").toString();
                    return "selected.Fast:" + selection;
                }).collect(Collectors.toList())
                .stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    
        System.out.println(counted);
    

    Edit 2: Solution to get count of all the elements inside the selection

        Map<String, Long> counted = jsonObj.stream().flatMap(x -> {
            JsonNode selection = x.get("selection");
            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(selection.fields(), 0), false);
        })
                .map(x -> x.getKey() + ":" + x.getValue()).collect(Collectors.toList())
                .stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        System.out.println(counted);