@Test
  public void findStatesWithPopulationOver10MillionAggregationExample() {
    /*
     //complex mongodb aggregation framework example from
     http://docs.mongodb.org/manual/tutorial/aggregation-examples/#largest-and-smallest-cities-by-state

     db.zipcodes.aggregate(
    	 	{
    		   $group: {
    		      _id:"$state",
    		      totalPop:{ $sum:"$pop"}
     			 }
    		},
    		{
     			$sort: { _id: 1, "totalPop": 1 }
     		},
    		{
    		   $match: {
    		      totalPop: { $gte:10*1000*1000 }
    		   }
    		}
    )
      */

    TypedAggregation<ZipInfo> agg =
        newAggregation(
            ZipInfo.class, //
            group("state") //
                .sum("population")
                .as("totalPop"), //
            sort(ASC, previousOperation(), "totalPop"), //
            match(where("totalPop").gte(10 * 1000 * 1000)) //
            );

    assertThat(agg, is(notNullValue()));
    assertThat(agg.toString(), is(notNullValue()));

    AggregationResults<StateStats> result = mongoTemplate.aggregate(agg, StateStats.class);
    assertThat(result, is(notNullValue()));
    assertThat(result.getMappedResults(), is(notNullValue()));
    assertThat(result.getMappedResults().size(), is(7));

    StateStats stateStats = result.getMappedResults().get(0);
    assertThat(stateStats, is(notNullValue()));
    assertThat(stateStats.id, is("CA"));
    assertThat(stateStats.state, is(nullValue()));
    assertThat(stateStats.totalPopulation, is(29760021));
  }
  /**
   * @see
   *     http://docs.mongodb.org/manual/tutorial/aggregation-examples/#return-the-five-most-common-likes
   */
  @Test
  public void returnFiveMostCommonLikesAggregationFrameworkExample() {

    createUserWithLikesDocuments();

    /*
    ...
     $group: {
    	      _id:"$like",
    	      number:{ $sum:1}
    			 }
     ...

    */

    TypedAggregation<UserWithLikes> agg =
        newAggregation(
            UserWithLikes.class, //
            unwind("likes"), //
            group("likes").count().as("number"), //
            sort(DESC, "number"), //
            limit(5), //
            sort(ASC, previousOperation()) //
            );

    assertThat(agg, is(notNullValue()));
    assertThat(agg.toString(), is(notNullValue()));

    AggregationResults<LikeStats> result = mongoTemplate.aggregate(agg, LikeStats.class);
    assertThat(result, is(notNullValue()));
    assertThat(result.getMappedResults(), is(notNullValue()));
    assertThat(result.getMappedResults().size(), is(5));

    assertLikeStats(result.getMappedResults().get(0), "a", 4);
    assertLikeStats(result.getMappedResults().get(1), "b", 2);
    assertLikeStats(result.getMappedResults().get(2), "c", 4);
    assertLikeStats(result.getMappedResults().get(3), "d", 2);
    assertLikeStats(result.getMappedResults().get(4), "e", 3);
  }
  @Test
  public void complexAggregationFrameworkUsageLargestAndSmallestCitiesByState() {
    /*
     //complex mongodb aggregation framework example from http://docs.mongodb.org/manual/tutorial/aggregation-examples/#largest-and-smallest-cities-by-state
    db.zipInfo.aggregate(
    	{
    	   $group: {
    	      _id: {
    	         state: '$state',
    	         city: '$city'
    	      },
    	      pop: {
    	         $sum: '$pop'
    	      }
    	   }
    	},
    	{
    	   $sort: {
    	      pop: 1,
    	      '_id.state': 1,
    	      '_id.city': 1
    	   }
    	},
    	{
    	   $group: {
    	      _id: '$_id.state',
    	      biggestCity: {
    	         $last: '$_id.city'
    	      },
    	      biggestPop: {
    	         $last: '$pop'
    	      },
    	      smallestCity: {
    	         $first: '$_id.city'
    	      },
    	      smallestPop: {
    	         $first: '$pop'
    	      }
    	   }
    	},
    	{
    	   $project: {
    	      _id: 0,
    	      state: '$_id',
    	      biggestCity: {
    	         name: '$biggestCity',
    	         pop: '$biggestPop'
    	      },
    	      smallestCity: {
    	         name: '$smallestCity',
    	         pop: '$smallestPop'
    	      }
    	   }
    	},
    	{
    	   $sort: {
    	      state: 1
    	   }
    	}
    )
    */

    TypedAggregation<ZipInfo> aggregation =
        newAggregation(
            ZipInfo.class, //
            group("state", "city").sum("population").as("pop"), //
            sort(ASC, "pop", "state", "city"), //
            group("state") //
                .last("city")
                .as("biggestCity") //
                .last("pop")
                .as("biggestPop") //
                .first("city")
                .as("smallestCity") //
                .first("pop")
                .as("smallestPop"), //
            project() //
                .and("state")
                .previousOperation() //
                .and("biggestCity")
                .nested(bind("name", "biggestCity").and("population", "biggestPop")) //
                .and("smallestCity")
                .nested(bind("name", "smallestCity").and("population", "smallestPop")), //
            sort(ASC, "state") //
            );

    assertThat(aggregation, is(notNullValue()));
    assertThat(aggregation.toString(), is(notNullValue()));

    AggregationResults<ZipInfoStats> result =
        mongoTemplate.aggregate(aggregation, ZipInfoStats.class);
    assertThat(result, is(notNullValue()));
    assertThat(result.getMappedResults(), is(notNullValue()));
    assertThat(result.getMappedResults().size(), is(51));

    ZipInfoStats firstZipInfoStats = result.getMappedResults().get(0);
    assertThat(firstZipInfoStats, is(notNullValue()));
    assertThat(firstZipInfoStats.id, is(nullValue()));
    assertThat(firstZipInfoStats.state, is("AK"));
    assertThat(firstZipInfoStats.smallestCity, is(notNullValue()));
    assertThat(firstZipInfoStats.smallestCity.name, is("CHEVAK"));
    assertThat(firstZipInfoStats.smallestCity.population, is(0));
    assertThat(firstZipInfoStats.biggestCity, is(notNullValue()));
    assertThat(firstZipInfoStats.biggestCity.name, is("ANCHORAGE"));
    assertThat(firstZipInfoStats.biggestCity.population, is(183987));

    ZipInfoStats lastZipInfoStats = result.getMappedResults().get(50);
    assertThat(lastZipInfoStats, is(notNullValue()));
    assertThat(lastZipInfoStats.id, is(nullValue()));
    assertThat(lastZipInfoStats.state, is("WY"));
    assertThat(lastZipInfoStats.smallestCity, is(notNullValue()));
    assertThat(lastZipInfoStats.smallestCity.name, is("LOST SPRINGS"));
    assertThat(lastZipInfoStats.smallestCity.population, is(6));
    assertThat(lastZipInfoStats.biggestCity, is(notNullValue()));
    assertThat(lastZipInfoStats.biggestCity.name, is("CHEYENNE"));
    assertThat(lastZipInfoStats.biggestCity.population, is(70185));
  }