Doctor Who
Doctor Who

Reputation: 792

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.

Upvotes: 0

Views: 744

Answers (4)

LeoTaylor
LeoTaylor

Reputation: 11

To output information about a field of the specified name in all levels of JSON records that have indefinite number of levels, the Java code will be long and complicated.

You can use SPL, the open-source Java package, to do this. It is easy and only one line of code is enough:

A
1 =json(file("data.json").read()).groups(#4.#3;count(~)).("selected.Fast:\""/#1/""-> occurred -"/#2/"times")

SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as count.splx and invoke it in Java as you call a stored procedure:

…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call count()");
st.execute();
…

Upvotes: 0

Pramod
Pramod

Reputation: 807

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);

Upvotes: 1

Dmitrii B
Dmitrii B

Reputation: 2860

You can use normally deserialize by jackson library and create object structure like that:

    @Setter
    @Getter
    @NoArgsConstructor
    static class Source {

        private long startAt;

        private long endAt;

        private long duration;

        private SourceSelection selection;

        private SourceDetails details;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    static class SourceSelection {

        private long speed;

        private long low;

        private long fast;

        private long medium;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    static class SourceDetails {

        private List<SourcePhase> phase;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    static class SourcePhase {

        private int value;

        private long timestamp;
    }

And then you need to deserialize your json to Source.class object:

List<Source> sourceList = new ObjectMapper().readValue(
        JSON,
        new ObjectMapper().getTypeFactory().constructCollectionType(List.class, Source.class)
);

When JSON is your source json

And then you can use a standart stream API for mapping, filtering, and counting:

    long result = sourceList.stream()
            .map(Source::getSelection)
            .filter(s-> s.getFast() != 0)
            .count();

Upvotes: 0

jon hanson
jon hanson

Reputation: 9408

I need to count how many times selected.Fast has occurred.

Is this what you're after?

List<Map<String, Object>> jsonObj = mapper.readValue(jArr, new TypeReference<List<Map<String, Object>>>(){});
                
long count = jsonObj.stream()
        .map(x -> x.get("selection").toString())
        .filter(s -> s.contains("selected.Fast"))
        .count()

System.out.println(count);

Upvotes: 2

Related Questions