【问题标题】:How do I nest a field within an Aggregation projection field in Spring Data Mongo如何在 Spring Data Mongo 的聚合投影字段中嵌套字段
【发布时间】:2016-10-11 21:52:45
【问题描述】:

手工编写时,我的聚合管道中的 $project 步骤如下所示:

    {  
     "$project":{  
        "DRIVE":{
           "componentSummary":{"manufacturer" : "$_id.DRIVE_manufacturer"},
           "componentCount":"$_id.DRIVE_componentCount"
        },
        "hostnames":1,
        "_id":0
     }
  }

我知道我可以使用ProjectionOperationBulder 创建单层嵌套(使用builder.nested),例如:

    {  
     "$project":{  
        "DRIVE":{  
           "manufacturer":"$_id.DRIVE_manufacturer"
        },
        "hostnames":1,
        "_id":0
     }
  }

但我似乎无法弄清楚如何嵌套另一个更深的级别,因为Field 接口只允许一个字符串名称和一个字符串目标,而不是能够将另一个Field 定义为目标。

谢谢!

【问题讨论】:

    标签: java mongodb spring-data aggregation-framework spring-data-mongodb


    【解决方案1】:

    对于其他为此苦苦挣扎的人——在撰写本文时,Spring Data Mongo 本身并不支持多级嵌套(稳定版本 1.9.5)。但是,从 1.9.3 开始,它确实支持custom AggregationExpressions,允许您自己定义行为。请注意,如果您沿着这条路线走,则必须主要手动构建查询的 JSON。我的实现非常快速和肮脏,但这里仅供参考。

          protected class NestedField implements Field {
    
    private String name;
    private List<Field> fields;
    
    public NestedField(String name, List<Field> fields) {
      this.name = name;
      this.fields = fields;
    }
    
    public List<Field> getFields() {
      return fields;
    }
    
    @Override
    public String getName() {
      return name;
    }
    
    private String escapeSystemVariables(String fieldTarget) {
      if (fieldTarget.startsWith("_id")) {
        return StringUtils.prependIfMissing(fieldTarget, "$");
      } else {
        return fieldTarget;
      }
    }
    
    private String encloseStringInQuotations(String quotable) {
      return JSON.serialize(quotable);
    }
    
    private String buildSingleFieldTarget(Field field) {
      if (field instanceof NestedField) {
        return String.join(":", encloseStringInQuotations(field.getName()), field.getTarget());
      }
      return String.join(":", encloseStringInQuotations(field.getName()), encloseStringInQuotations(escapeSystemVariables(
        field.getTarget())));
    }
    
    private String buildFieldTargetList(List<Field> fields) {
      List<String> fieldStrings = new ArrayList<>();
      fields.forEach(field -> {
        fieldStrings.add(buildSingleFieldTarget(field));
      });
      return Joiner.on(",").skipNulls().join(fieldStrings);
    }
    
    @Override
    public String getTarget() {
      // TODO Auto-generated method stub
      return String.format("{%s}", buildFieldTargetList(fields));
    }
    
    
    @Override
    public boolean isAliased() {
      return true;
    }
    

    }

        protected class NestedProjection implements AggregationExpression {
    
    private List<Field> projectedFields;
    
    public NestedProjection(List<Field> projectedFields) {
      this.projectedFields = projectedFields;
    
    }@Override
    public DBObject toDbObject(AggregationOperationContext context) {
      DBObject projectionExpression = new BasicDBObject();
      for(Field f : projectedFields) {
        //this is necessary because if we just put f.getTarget(), spring-mongo will attempt to JSON-escape the string
        DBObject target = (DBObject) com.mongodb.util.JSON.parse(f.getTarget());
          projectionExpression.put(f.getName(), target);
    
    
      }
      return projectionExpression;
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-01
      • 1970-01-01
      • 2021-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多