使用流将地图列表的特定条目提取到新地图中

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

给定一个 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"
       }
    ]
}

如何通过流将 fieldNamefieldLabel 的值提取到以下内容中?

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

我尝试了以下方法,但我卡在了获得 cardFields 列表值的部分。

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

您也许可以像这样解析您的文档:

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

如果你不介意投很多,你可以尝试以下:

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

或者您可以通过以下方式发出省略转换:

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

这是完整的例子运行 java 17:

import org.bson.Document;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


public class Bson {

 private String json=
           """
                {
                  "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"
                      }
                    ]
                  }
                }     
        """;

public static void main(String[] args) {

    Bson bson = new Bson();
    Document document = Document.parse(bson.json);

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

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


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

这是一个流的工作解决方案:

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

这可能是我写过的最糟糕的代码 - 绝对不可读,您无法调试它。我建议您不要将流用于此特定任务,它不是适合它的工具。所以这是另一个使用 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());

它更短、更易读,您可以根据需要对其进行调试,而且它的性能可能更高。我会说它总体上好多了。