Home > Enterprise >  Using streams to extract specific entries of a List of Maps in to a new Map
Using streams to extract specific entries of a List of Maps in to a new Map

Time:01-11

Given a org.bson.Document

{  
  "doneDate":"",
  "todoEstimates":"",
  "forecastDate":"",
  "cardType":{
    "projectData":[
      {
        "color":"#ffcd03",
        "boardId":"30022"
      },
      {
        "color":"#ffcd03",
        "boardId":"1559427"
      }
    ],
    "cardFields":[
      {
        "fieldName":"id",
        "fieldLabel":"Unique ID",
        "fieldType":"Integer",
        "itemType":"Long",
        "isRequired":"NO",
        "isReadOnly":"Yes",
        "isDisabled":"NO",
        "inputMethod":"System Generated",
        "defaultValue":null,
        "isUserType":"No"
      },
      {
        "fieldName":"name",
        "fieldLabel":"Title",
        "fieldType":"Single-Line Text",
        "itemType":"String",
        "isRequired":"Yes",
        "isReadOnly":"NO",
        "isDisabled":"NO",
        "inputMethod":"Manual Entry",
        "defaultValue":null,
        "isUserType":"No"
       }
    ]
}

How do I extract the values of fieldName and fieldLabel via streams into the following?

{
   "id": "Unique ID",
   "name:" "Title",
   ...
}

I tried the following but I get stuck at the part where I get value of the cardFields list.

document.entrySet().stream().filter(e -> e.getKey().equals("cardType"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
.entrySet().stream().filter(e -> e.getKey().equals("cardFields"))
        .map(e -> (Map)e.getValue()).toList();

CodePudding user response:

Here is a working solution with streams:

Map<String, Object> fields = ((List<Map<String, Object>>) ((Map<String, Object>) document.entrySet()
            .stream()
            .filter(entry -> entry.getKey().equals("cardType"))
            .findFirst()
            .orElseThrow(() -> new RuntimeException("card type not found"))
            .getValue())
            .entrySet()
            .stream()
            .filter(entry -> entry.getKey().equals("cardFields"))
            .findFirst()
            .orElseThrow(() -> new RuntimeException("card fields not found"))
            .getValue())
            .stream()
            .collect(Collectors.toMap(el -> el.get("fieldName").toString(), element -> element.get("fieldLabel")));
Document result = new Document(fields);
System.out.println(result.toJson());

That's probably the worst code i have written - absolutely unreadable and you can't debug it. I would suggest that you do not use stream for this particular task, it isn't the right tool for it. So here is another working solution using Map.get(key):

Map<String, Object> cardType = (Map<String, Object>) document.get("cardType");
List<Map<String, Object>> cardFields = (List<Map<String, Object>>) cardType.get("cardFields");
Document result = new Document();
cardFields.forEach(cardField -> result.put((String) cardField.get("fieldName"), cardField.get("fieldLabel")));
System.out.println(result.toJson());

This is shorter, readable, you can debug it if needed and probably it's more performant. I'd say it's much better overall.

CodePudding user response:

You may be able to parse your document like this:

Document cardType = document.get("cardType", Document.class);
final Class<? extends List> listOfMaps = new ArrayList<Map<String, String>>().getClass();
List<Map<String, String>> fields = cardType.get("cardFields", listOfMaps);
fields.stream().map(f -> {
    System.out.println(f.get("fieldName")   ": "   f.get("fieldLabel"));
    // here you can construct your new object
}).collect(Collectors.toList());

CodePudding user response:

If you don't mind casting a lot, you could try following:

    List cardFields = (List) ((Map) document.get("cardType")).get("cardFields");

    Map<String, String> map = (Map) cardFields.stream()
            .collect(Collectors.toMap(cf -> ((Document) cf).getString("fieldName"),
                    cv -> ((Document) cv).getString("fieldLabel")));
    
    System.out.println(map);

or you can emit omit the casting with the following:

    List<Document> carFields = document.get("cardType", Document.class)
                                       .getList("cardFields", Document.class);
    Map<String, String> map = carFields.stream()
            .collect(Collectors.toMap(k -> k.getString("fieldName"), 
                                      v -> v.getString("fieldLabel")));
    System.out.println(map);
  •  Tags:  
  • Related