0

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.

4 Answers 4

2

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);
Sign up to request clarification or add additional context in comments.

1 Comment

Sorry I think my question was not clear, I need how many times selected.Fast:"7173" -> occurred - 5 times selected.Fast:"123" -> occurred - 2 times
1

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

7 Comments

Thanks for the response There is a error in this line String selection = x.get("selection").get("selected.Fast").asText(); The method get(int) in the type JsonArray is not applicable for the arguments (String)
I am using com.fasterxml.jackson.databind 2.6.7.1, may be there is version mismatch. Which jackson version you are using ?
I am using 2.8.5
I think you imported wrong JsonNode or something else is wrong. Here x should be a type of JsonNode (to be precise, com.fasterxml.jackson.databind.node.ObjectNode). Please check this link fasterxml.github.io/jackson-databind/javadoc/2.8/com/fasterxml/…
Thanks Found the issue, working now, Thanks for your help
|
0

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

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.