title: Spring data Match and Filter Nested Array
body: <p>How can extract data from nested array ?</p>
  
  <p>I want to extract the array item "values" where wind_speed parameter value is between vitRange.min and vitRange.max (same condition for twaRange and wind direction)</p>
  
  <p>Data :</p>
  
  <pre><code>{
      "name" : "race"
      ,"polaire" : [
          {
              "voile" : "foc"
              , "matrice" :[
                  {
                      "vitRange" : { "min" : 0, "max" : 4}
                      ,"twaRange" : { "min" : 0, "max" : 30}
                      ,"values" : [0, 0, 0, 2.4]
                  },
                  {
                      "vitRange" : { "min" : 4, "max" : 6}
                      ,"twaRange" : { "min" : 30, "max" : 33}
                      ,"values" : [0, 0, 2.4, 3.7]
                  }
              ]
          },
          {
              "voile" : "spi"
              , "matrice" :[
                  {
                      "vitRange" : { "min" : 0, "max" : 4}
                      ,"twaRange" : { "min" : 0, "max" : 30}
                      ,"values" : [0, 0, 0, 1.4]
                  },
                  {
                      "vitRange" : { "min" : 4, "max" : 6}
                      ,"twaRange" : { "min" : 30, "max" : 33}
                      ,"values" : [0, 0, 1.4, 2.2]
                  }
              ]
          }
      ]
  }
  </code></pre>
  
  <p>First approach : </p>
  
  <pre><code>Query query = new Query(
    Criteria.where("name").is(name)
    .andOperator(
      Criteria.where("polaire.voile").is(sail),
      Criteria.where("polaire.matrice.twaRange.max").lt(wind_direction),
      Criteria.where("polaire.matrice.twaRange.min").gte(wind_direction),
      Criteria.where("polaire.matrice.vitRange.max").lt(wind_speed),
      Criteria.where("polaire.matrice.vitRange.min").gte(wind_speed)
    )
  );
  query.fields().include("polaire.matrice.values");
  Polaires data = mongoTemplate.findOne(query, Polaires.class);
  </code></pre>
  
  <p>2nd approach:</p>
  
  <pre><code>Criteria findPolaireCriteria = Criteria.where("name").is(name);
  Criteria findValueCriteria = Criteria.where("polaire").elemMatch(Criteria.where("voile").is(sail))
        .andOperator(
              Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("max").lt(wind_direction)),
              Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("min").gte(wind_direction)),
              Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("max").lt(wind_speed)),
              Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("min").gte(wind_speed)));
  
  BasicQuery query = new BasicQuery(findPolaireCriteria.getCriteriaObject(), findValueCriteria.getCriteriaObject());
  
  query.fields().include("polaire.matrice.values");
  Polaires data = mongoTemplate.findOne(query, Polaires.class);
  </code></pre>
  
  <p>Last approach:
  (cf. <a href="https://stackoverflow.com/questions/41467386/query-a-document-and-all-of-its-subdocuments-that-match-a-condition-in-mongodb">Query a document and all of its subdocuments that match a condition in mongodb (using spring)</a>)</p>
  
  <pre><code>Aggregation aggregation = newAggregation(
          match(Criteria.where("name").is(name)
                  .and("polaire").elemMatch(Criteria.where("voile").is(sail))),
          project( "_id", "matrice")
              .and(new AggregationExpression() {
              @Override
              public DBObject toDbObject(AggregationOperationContext aggregationOperationContext ) {
                  DBObject filter = new BasicDBObject("input", "$matrice")
                      .append("as", "result")
                      .append("cond",
                          new BasicDBObject("$and", Arrays.&lt;Object&gt; asList(
                                  new BasicDBObject("$gte", Arrays.&lt;Object&gt; asList("$$result.vitRange.min", 0)),
                                  new BasicDBObject("$lt", Arrays.&lt;Object&gt; asList("$$result.vitRange.max", 4))
                                  )
                          )
                  );
                  return new BasicDBObject("$filter", filter);
              }
          }).as("matrice")
  );
  
  List&lt;BasicDBObject&gt; dbObjects = mongoTemplate.aggregate(aggregation, "collectionname", BasicDBObject.class).getMappedResults();     
  </code></pre>
  
  <p>Or Another one...</p>
  
  <pre><code>List&lt;AggregationOperation&gt; list = new ArrayList&lt;AggregationOperation&gt;();
  list.add(Aggregation.match(Criteria.where("name").is(name)));
  list.add(Aggregation.unwind("polaire"));
  list.add(Aggregation.match(Criteria.where("polaire.voile").is(sail)));
  list.add(Aggregation.unwind("polaire.matrice"));
  list.add(Aggregation.match(Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("max").lt(wind_direction))));
  list.add(Aggregation.match(Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("min").gte(wind_direction))));
  list.add(Aggregation.match(Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("max").lt(wind_speed))));
  list.add(Aggregation.match(Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("min").gte(wind_speed))));
  list.add(Aggregation.group("id", "polaire.matrice").push("polaire.matrice.values").as("values"));
  list.add(Aggregation.project("polaire.matrice","values"));
  
  TypedAggregation&lt;Polaires&gt; agg = Aggregation.newAggregation(Polaires.class, list);
  List&lt;BasicDBObject&gt; dbObjects = mongoTemplate.aggregate(agg, "collectionname", BasicDBObject.class).getMappedResults();     
  </code></pre>
  
  <p>Turn around again and again on the forum but none of them help me.
  The issue is probably on working to the json structure (adapt it to easily request) ?</p>
  
  <p>Thanks </p>