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