@Test
  public void shouldDetectResultMismatch() {

    createTagDocuments();

    Aggregation aggregation =
        newAggregation( //
            project("tags"), //
            unwind("tags"), //
            group("tags") //
                .count()
                .as("count"), // count field not present
            limit(2) //
            );

    AggregationResults<TagCount> results =
        mongoTemplate.aggregate(aggregation, INPUT_COLLECTION, TagCount.class);

    assertThat(results, is(notNullValue()));
    assertThat(results.getServerUsed(), is("/127.0.0.1:27017"));

    List<TagCount> tagCount = results.getMappedResults();

    assertThat(tagCount, is(notNullValue()));
    assertThat(tagCount.size(), is(2));
    assertTagCount(null, 0, tagCount.get(0));
    assertTagCount(null, 0, tagCount.get(1));
  }
  @Test
  public void testUsingUpdateWithMultipleSet() throws Exception {

    template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);

    PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
    p1.setFirstName("Sven");
    p1.setAge(11);
    template.insert(p1);
    PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
    p2.setFirstName("Mary");
    p2.setAge(21);
    template.insert(p2);

    Update u = new Update().set("firstName", "Bob").set("age", 10);

    WriteResult wr = template.updateMulti(new Query(), u, PersonWithIdPropertyOfTypeObjectId.class);

    assertThat(wr.getN(), is(2));

    Query q1 = new Query(Criteria.where("age").in(11, 21));
    List<PersonWithIdPropertyOfTypeObjectId> r1 =
        template.find(q1, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(r1.size(), is(0));
    Query q2 = new Query(Criteria.where("age").is(10));
    List<PersonWithIdPropertyOfTypeObjectId> r2 =
        template.find(q2, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(r2.size(), is(2));
    for (PersonWithIdPropertyOfTypeObjectId p : r2) {
      assertThat(p.getAge(), is(10));
      assertThat(p.getFirstName(), is("Bob"));
    }
  }
  @Test
  public void shouldAggregate() {

    createTagDocuments();

    Aggregation agg =
        newAggregation( //
            project("tags"), //
            unwind("tags"), //
            group("tags") //
                .count()
                .as("n"), //
            project("n") //
                .and("tag")
                .previousOperation(), //
            sort(DESC, "n") //
            );

    AggregationResults<TagCount> results =
        mongoTemplate.aggregate(agg, INPUT_COLLECTION, TagCount.class);

    assertThat(results, is(notNullValue()));
    assertThat(results.getServerUsed(), is("/127.0.0.1:27017"));

    List<TagCount> tagCount = results.getMappedResults();

    assertThat(tagCount, is(notNullValue()));
    assertThat(tagCount.size(), is(3));

    assertTagCount("spring", 3, tagCount.get(0));
    assertTagCount("mongodb", 2, tagCount.get(1));
    assertTagCount("nosql", 1, tagCount.get(2));
  }
  @Test
  public void testUsingAnInQueryWithStringId() throws Exception {

    template.remove(new Query(), PersonWithIdPropertyOfTypeString.class);

    PersonWithIdPropertyOfTypeString p1 = new PersonWithIdPropertyOfTypeString();
    p1.setFirstName("Sven");
    p1.setAge(11);
    template.insert(p1);
    PersonWithIdPropertyOfTypeString p2 = new PersonWithIdPropertyOfTypeString();
    p2.setFirstName("Mary");
    p2.setAge(21);
    template.insert(p2);
    PersonWithIdPropertyOfTypeString p3 = new PersonWithIdPropertyOfTypeString();
    p3.setFirstName("Ann");
    p3.setAge(31);
    template.insert(p3);
    PersonWithIdPropertyOfTypeString p4 = new PersonWithIdPropertyOfTypeString();
    p4.setFirstName("John");
    p4.setAge(41);
    template.insert(p4);

    Query q1 = new Query(Criteria.where("age").in(11, 21, 41));
    List<PersonWithIdPropertyOfTypeString> results1 =
        template.find(q1, PersonWithIdPropertyOfTypeString.class);
    Query q2 = new Query(Criteria.where("firstName").in("Ann", "Mary"));
    List<PersonWithIdPropertyOfTypeString> results2 =
        template.find(q2, PersonWithIdPropertyOfTypeString.class);
    Query q3 = new Query(Criteria.where("id").in(p3.getId(), p4.getId()));
    List<PersonWithIdPropertyOfTypeString> results3 =
        template.find(q3, PersonWithIdPropertyOfTypeString.class);
    assertThat(results1.size(), is(3));
    assertThat(results2.size(), is(2));
    assertThat(results3.size(), is(2));
  }
  @Test
  public void shouldAggregateEmptyCollection() {

    Aggregation aggregation =
        newAggregation( //
            project("tags"), //
            unwind("tags"), //
            group("tags") //
                .count()
                .as("n"), //
            project("n") //
                .and("tag")
                .previousOperation(), //
            sort(DESC, "n") //
            );

    AggregationResults<TagCount> results =
        mongoTemplate.aggregate(aggregation, INPUT_COLLECTION, TagCount.class);

    assertThat(results, is(notNullValue()));
    assertThat(results.getServerUsed(), is("/127.0.0.1:27017"));

    List<TagCount> tagCount = results.getMappedResults();

    assertThat(tagCount, is(notNullValue()));
    assertThat(tagCount.size(), is(0));
  }
  @Test
  public void testRemovingDocument() throws Exception {

    PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
    p1.setFirstName("Sven_to_be_removed");
    p1.setAge(51);
    template.insert(p1);

    Query q1 = new Query(Criteria.where("id").is(p1.getId()));
    PersonWithIdPropertyOfTypeObjectId found1 =
        template.findOne(q1, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(found1, notNullValue());
    Query _q = new Query(Criteria.where("_id").is(p1.getId()));
    template.remove(_q, PersonWithIdPropertyOfTypeObjectId.class);
    PersonWithIdPropertyOfTypeObjectId notFound1 =
        template.findOne(q1, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(notFound1, nullValue());

    PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
    p2.setFirstName("Bubba_to_be_removed");
    p2.setAge(51);
    template.insert(p2);

    Query q2 = new Query(Criteria.where("id").is(p2.getId()));
    PersonWithIdPropertyOfTypeObjectId found2 =
        template.findOne(q2, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(found2, notNullValue());
    template.remove(q2, PersonWithIdPropertyOfTypeObjectId.class);
    PersonWithIdPropertyOfTypeObjectId notFound2 =
        template.findOne(q2, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(notFound2, nullValue());
  }
  @Test
  public void testUsingRegexQueryWithOptions() throws Exception {

    template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);

    PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
    p1.setFirstName("Sven");
    p1.setAge(11);
    template.insert(p1);
    PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
    p2.setFirstName("Mary");
    p2.setAge(21);
    template.insert(p2);
    PersonWithIdPropertyOfTypeObjectId p3 = new PersonWithIdPropertyOfTypeObjectId();
    p3.setFirstName("Ann");
    p3.setAge(31);
    template.insert(p3);
    PersonWithIdPropertyOfTypeObjectId p4 = new PersonWithIdPropertyOfTypeObjectId();
    p4.setFirstName("samantha");
    p4.setAge(41);
    template.insert(p4);

    Query q1 = new Query(Criteria.where("firstName").regex("S.*"));
    List<PersonWithIdPropertyOfTypeObjectId> results1 =
        template.find(q1, PersonWithIdPropertyOfTypeObjectId.class);
    Query q2 = new Query(Criteria.where("firstName").regex("S.*", "i"));
    List<PersonWithIdPropertyOfTypeObjectId> results2 =
        template.find(q2, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(results1.size(), is(1));
    assertThat(results2.size(), is(2));
  }
  @Test
  public void testUsingAnOrQuery() throws Exception {

    template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);

    PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
    p1.setFirstName("Sven");
    p1.setAge(11);
    template.insert(p1);
    PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
    p2.setFirstName("Mary");
    p2.setAge(21);
    template.insert(p2);
    PersonWithIdPropertyOfTypeObjectId p3 = new PersonWithIdPropertyOfTypeObjectId();
    p3.setFirstName("Ann");
    p3.setAge(31);
    template.insert(p3);
    PersonWithIdPropertyOfTypeObjectId p4 = new PersonWithIdPropertyOfTypeObjectId();
    p4.setFirstName("John");
    p4.setAge(41);
    template.insert(p4);

    Query orQuery =
        new Query(new Criteria().orOperator(where("age").in(11, 21), where("age").is(31)));
    List<PersonWithIdPropertyOfTypeObjectId> results =
        template.find(orQuery, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(results.size(), is(3));
    for (PersonWithIdPropertyOfTypeObjectId p : results) {
      assertThat(p.getAge(), isOneOf(11, 21, 31));
    }
  }
  @Test
  public void insertsSimpleEntityCorrectly() throws Exception {

    Person person = new Person("Oliver");
    person.setAge(25);
    template.insert(person);

    List<Person> result =
        template.find(new Query(Criteria.where("_id").is(person.getId())), Person.class);
    assertThat(result.size(), is(1));
    assertThat(result, hasItem(person));
  }
 @Test
 public void testFindAndUpdateUpsert() {
   template.insert(new Person("Tom", 21));
   template.insert(new Person("Dick", 22));
   Query query = new Query(Criteria.where("firstName").is("Harry"));
   Update update = new Update().set("age", 23);
   Person p =
       template.findAndModify(
           query, update, new FindAndModifyOptions().upsert(true).returnNew(true), Person.class);
   assertThat(p.getFirstName(), is("Harry"));
   assertThat(p.getAge(), is(23));
 }
  /** @see DATADOC-230 */
  @Test
  public void removesEntityFromCollection() {

    template.remove(new Query(), "mycollection");

    Person person = new Person("Dave");

    template.save(person, "mycollection");
    assertThat(template.findAll(TestClass.class, "mycollection").size(), is(1));

    template.remove(person, "mycollection");
    assertThat(template.findAll(Person.class, "mycollection").isEmpty(), is(true));
  }
  @Test
  public void returnsEntityWhenQueryingForDateTime() {

    DateTime dateTime = new DateTime(2011, 3, 3, 12, 0, 0, 0);
    TestClass testClass = new TestClass(dateTime);
    mappingTemplate.save(testClass);

    List<TestClass> testClassList =
        mappingTemplate.find(
            new Query(Criteria.where("myDate").is(dateTime.toDate())), TestClass.class);
    assertThat(testClassList.size(), is(1));
    assertThat(testClassList.get(0).myDate, is(testClass.myDate));
  }
  /** @see DATADOC-183 */
  @Test
  public void countsDocumentsCorrectly() {

    assertThat(template.count(new Query(), Person.class), is(0L));

    Person dave = new Person("Dave");
    Person carter = new Person("Carter");

    template.save(dave);
    template.save(carter);

    assertThat(template.count(null, Person.class), is(2L));
    assertThat(template.count(query(where("firstName").is("Carter")), Person.class), is(1L));
  }
  /** @see DATADOC-349 */
  @Test
  public void removesEntityWithAnnotatedIdIfIdNeedsMassaging() {

    String id = new ObjectId().toString();

    Sample sample = new Sample();
    sample.id = id;

    template.save(sample);

    assertThat(template.findOne(query(where("id").is(id)), Sample.class).id, is(id));

    template.remove(sample);
    assertThat(template.findOne(query(where("id").is(id)), Sample.class), is(nullValue()));
  }
  @Test
  public void testFindAndRemove() throws Exception {

    Message m1 = new Message("Hello Spring");
    template.insert(m1);
    Message m2 = new Message("Hello Mongo");
    template.insert(m2);

    Query q = new Query(Criteria.where("text").regex("^Hello.*"));
    Message found1 = template.findAndRemove(q, Message.class);
    Message found2 = template.findAndRemove(q, Message.class);
    // Message notFound = template.findAndRemove(q, Message.class);
    DBObject notFound = template.getCollection("").findAndRemove(q.getQueryObject());
    assertThat(found1, notNullValue());
    assertThat(found2, notNullValue());
    assertThat(notFound, nullValue());
  }
  @Test
  public void testAddingToList() {
    PersonWithAList p = new PersonWithAList();
    p.setFirstName("Sven");
    p.setAge(22);
    template.insert(p);

    Query q1 = new Query(Criteria.where("id").is(p.getId()));
    PersonWithAList p2 = template.findOne(q1, PersonWithAList.class);
    assertThat(p2, notNullValue());
    assertThat(p2.getWishList().size(), is(0));

    p2.addToWishList("please work!");

    template.save(p2);

    PersonWithAList p3 = template.findOne(q1, PersonWithAList.class);
    assertThat(p3, notNullValue());
    assertThat(p3.getWishList().size(), is(1));

    Friend f = new Friend();
    p.setFirstName("Erik");
    p.setAge(21);

    p3.addFriend(f);
    template.save(p3);

    PersonWithAList p4 = template.findOne(q1, PersonWithAList.class);
    assertThat(p4, notNullValue());
    assertThat(p4.getWishList().size(), is(1));
    assertThat(p4.getFriends().size(), is(1));
  }
  /**
   * @see DATAMONGO-753
   * @see http
   *     ://stackoverflow.com/questions/18653574/spring-data-mongodb-aggregation-framework-invalid-reference-in-group
   *     -operati
   */
  @Test
  public void allowsNestedFieldReferencesAsGroupIdsInGroupExpressions() {

    mongoTemplate.insert(
        new DATAMONGO753().withPDs(new PD("A", 1), new PD("B", 1), new PD("C", 1)));
    mongoTemplate.insert(
        new DATAMONGO753().withPDs(new PD("B", 1), new PD("B", 1), new PD("C", 1)));

    TypedAggregation<DATAMONGO753> agg =
        newAggregation(
            DATAMONGO753.class, //
            unwind("pd"), //
            group("pd.pDch") // the nested field expression
                .sum("pd.up")
                .as("uplift"), //
            project("_id", "uplift"));

    AggregationResults<DBObject> result = mongoTemplate.aggregate(agg, DBObject.class);
    List<DBObject> stats = result.getMappedResults();

    assertThat(stats.size(), is(3));
    assertThat(stats.get(0).get("_id").toString(), is("C"));
    assertThat((Integer) stats.get(0).get("uplift"), is(2));
    assertThat(stats.get(1).get("_id").toString(), is("B"));
    assertThat((Integer) stats.get(1).get("uplift"), is(3));
    assertThat(stats.get(2).get("_id").toString(), is("A"));
    assertThat((Integer) stats.get(2).get("uplift"), is(1));
  }
  /** @see DATADOC-240, DATADOC-212 */
  @Test
  public void updatesObjectIdsCorrectly() {

    PersonWithIdPropertyOfTypeObjectId person = new PersonWithIdPropertyOfTypeObjectId();
    person.setId(new ObjectId());
    person.setFirstName("Dave");

    template.save(person);
    template.updateFirst(
        query(where("id").is(person.getId())),
        update("firstName", "Carter"),
        PersonWithIdPropertyOfTypeObjectId.class);

    PersonWithIdPropertyOfTypeObjectId result =
        template.findById(person.getId(), PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(result, is(notNullValue()));
    assertThat(result.getId(), is(person.getId()));
    assertThat(result.getFirstName(), is("Carter"));
  }
  @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));
  }
  @Test
  public void testUsingInQueryWithList() throws Exception {

    template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);

    PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
    p1.setFirstName("Sven");
    p1.setAge(11);
    template.insert(p1);
    PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
    p2.setFirstName("Mary");
    p2.setAge(21);
    template.insert(p2);
    PersonWithIdPropertyOfTypeObjectId p3 = new PersonWithIdPropertyOfTypeObjectId();
    p3.setFirstName("Ann");
    p3.setAge(31);
    template.insert(p3);
    PersonWithIdPropertyOfTypeObjectId p4 = new PersonWithIdPropertyOfTypeObjectId();
    p4.setFirstName("John");
    p4.setAge(41);
    template.insert(p4);

    List<Integer> l1 = new ArrayList<Integer>();
    l1.add(11);
    l1.add(21);
    l1.add(41);
    Query q1 = new Query(Criteria.where("age").in(l1));
    List<PersonWithIdPropertyOfTypeObjectId> results1 =
        template.find(q1, PersonWithIdPropertyOfTypeObjectId.class);
    Query q2 = new Query(Criteria.where("age").in(l1.toArray()));
    List<PersonWithIdPropertyOfTypeObjectId> results2 =
        template.find(q2, PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(results1.size(), is(3));
    assertThat(results2.size(), is(3));
    try {
      List<Integer> l2 = new ArrayList<Integer>();
      l2.add(31);
      Query q3 = new Query(Criteria.where("age").in(l1, l2));
      template.find(q3, PersonWithIdPropertyOfTypeObjectId.class);
      Assert.fail("Should have trown an InvalidDocumentStoreApiUsageException");
    } catch (InvalidMongoDbApiUsageException e) {
    }
  }
  @Test
  public void testEnsureIndex() throws Exception {

    Person p1 = new Person("Oliver");
    p1.setAge(25);
    template.insert(p1);
    Person p2 = new Person("Sven");
    p2.setAge(40);
    template.insert(p2);

    template
        .indexOps(Person.class)
        .ensureIndex(new Index().on("age", Order.DESCENDING).unique(Duplicates.DROP));

    DBCollection coll = template.getCollection(template.getCollectionName(Person.class));
    List<DBObject> indexInfo = coll.getIndexInfo();
    assertThat(indexInfo.size(), is(2));
    String indexKey = null;
    boolean unique = false;
    boolean dropDupes = false;
    for (DBObject ix : indexInfo) {
      if ("age_-1".equals(ix.get("name"))) {
        indexKey = ix.get("key").toString();
        unique = (Boolean) ix.get("unique");
        dropDupes = (Boolean) ix.get("dropDups");
      }
    }
    assertThat(indexKey, is("{ \"age\" : -1}"));
    assertThat(unique, is(true));
    assertThat(dropDupes, is(true));

    List<IndexInfo> indexInfoList = template.indexOps(Person.class).getIndexInfo();
    System.out.println(indexInfoList);
    assertThat(indexInfoList.size(), is(2));
    IndexInfo ii = indexInfoList.get(1);
    assertThat(ii.isUnique(), is(true));
    assertThat(ii.isDropDuplicates(), is(true));
    assertThat(ii.isSparse(), is(false));
    assertThat(ii.getFieldSpec().containsKey("age"), is(true));
    assertThat(ii.getFieldSpec().containsValue(Order.DESCENDING), is(true));
  }
  /**
   * @see DATAMONGO-753
   * @see http
   *     ://stackoverflow.com/questions/18653574/spring-data-mongodb-aggregation-framework-invalid-reference-in-group
   *     -operati
   */
  @Test
  public void aliasesNestedFieldInProjectionImmediately() {

    mongoTemplate.insert(
        new DATAMONGO753().withPDs(new PD("A", 1), new PD("B", 1), new PD("C", 1)));
    mongoTemplate.insert(
        new DATAMONGO753().withPDs(new PD("B", 1), new PD("B", 1), new PD("C", 1)));

    TypedAggregation<DATAMONGO753> agg =
        newAggregation(
            DATAMONGO753.class, //
            unwind("pd"), //
            project().and("pd.up").as("up"));

    AggregationResults<DBObject> results = mongoTemplate.aggregate(agg, DBObject.class);
    List<DBObject> mappedResults = results.getMappedResults();

    assertThat(mappedResults, hasSize(6));
    for (DBObject element : mappedResults) {
      assertThat(element.get("up"), is((Object) 1));
    }
  }
  /**
   * @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);
  }
  /** @see DATAMONGO-234 */
  @Test
  public void testFindAndUpdate() {

    template.insert(new Person("Tom", 21));
    template.insert(new Person("Dick", 22));
    template.insert(new Person("Harry", 23));

    Query query = new Query(Criteria.where("firstName").is("Harry"));
    Update update = new Update().inc("age", 1);
    Person p = template.findAndModify(query, update, Person.class); // return old
    assertThat(p.getFirstName(), is("Harry"));
    assertThat(p.getAge(), is(23));
    p = template.findOne(query, Person.class);
    assertThat(p.getAge(), is(24));

    p = template.findAndModify(query, update, Person.class, "person");
    assertThat(p.getAge(), is(24));
    p = template.findOne(query, Person.class);
    assertThat(p.getAge(), is(25));

    p =
        template.findAndModify(
            query, update, new FindAndModifyOptions().returnNew(true), Person.class);
    assertThat(p.getAge(), is(26));

    p = template.findAndModify(query, update, null, Person.class, "person");
    assertThat(p.getAge(), is(26));
    p = template.findOne(query, Person.class);
    assertThat(p.getAge(), is(27));

    Query query2 = new Query(Criteria.where("firstName").is("Mary"));
    p =
        template.findAndModify(
            query2, update, new FindAndModifyOptions().returnNew(true).upsert(true), Person.class);
    assertThat(p.getFirstName(), is("Mary"));
    assertThat(p.getAge(), is(1));
  }
  /**
   * Imports the sample dataset (zips.json) if necessary (e.g. if it doen't exist yet). The dataset
   * can originally be found on the mongodb aggregation framework example website:
   *
   * @see http://docs.mongodb.org/manual/tutorial/aggregation-examples/.
   */
  private void initSampleDataIfNecessary() {

    if (!initialized) {

      CommandResult result = mongoTemplate.executeCommand("{ buildInfo: 1 }");
      Object version = result.get("version");
      LOGGER.debug("Server uses MongoDB Version: {}", version);

      mongoTemplate.dropCollection(ZipInfo.class);
      mongoTemplate.execute(
          ZipInfo.class,
          new CollectionCallback<Void>() {

            @Override
            public Void doInCollection(DBCollection collection)
                throws MongoException, DataAccessException {

              Scanner scanner = null;
              try {
                scanner =
                    new Scanner(
                        new BufferedInputStream(
                            new ClassPathResource("zips.json").getInputStream()));
                while (scanner.hasNextLine()) {
                  String zipInfoRecord = scanner.nextLine();
                  collection.save((DBObject) JSON.parse(zipInfoRecord));
                }
              } catch (Exception e) {
                if (scanner != null) {
                  scanner.close();
                }
                throw new RuntimeException("Could not load mongodb sample dataset!", e);
              }

              return null;
            }
          });

      long count = mongoTemplate.count(new Query(), ZipInfo.class);
      assertThat(count, is(29467L));

      initialized = true;
    }
  }
  @Test
  public void testWriteConcernResolver() {

    PersonWithIdPropertyOfTypeObjectId person = new PersonWithIdPropertyOfTypeObjectId();
    person.setId(new ObjectId());
    person.setFirstName("Dave");

    template.setWriteConcern(WriteConcern.NONE);
    template.save(person);
    WriteResult result =
        template.updateFirst(
            query(where("id").is(person.getId())),
            update("firstName", "Carter"),
            PersonWithIdPropertyOfTypeObjectId.class);
    WriteConcern lastWriteConcern = result.getLastConcern();
    assertThat(lastWriteConcern, equalTo(WriteConcern.NONE));

    FsyncSafeWriteConcernResolver resolver = new FsyncSafeWriteConcernResolver();
    template.setWriteConcernResolver(resolver);
    Query q = query(where("_id").is(person.getId()));
    Update u = update("firstName", "Carter");
    result = template.updateFirst(q, u, PersonWithIdPropertyOfTypeObjectId.class);
    lastWriteConcern = result.getLastConcern();
    assertThat(lastWriteConcern, equalTo(WriteConcern.FSYNC_SAFE));

    MongoAction lastMongoAction = resolver.getMongoAction();
    assertThat(lastMongoAction.getCollectionName(), is("personWithIdPropertyOfTypeObjectId"));
    assertThat(lastMongoAction.getDefaultWriteConcern(), equalTo(WriteConcern.NONE));
    assertThat(lastMongoAction.getDocument(), notNullValue());
    assertThat(
        lastMongoAction.getEntityClass().toString(),
        is(PersonWithIdPropertyOfTypeObjectId.class.toString()));
    assertThat(lastMongoAction.getMongoActionOperation(), is(MongoActionOperation.UPDATE));
    assertThat(lastMongoAction.getQuery(), equalTo(q.getQueryObject()));
    assertThat(lastMongoAction.getDocument(), equalTo(u.getUpdateObject()));
  }
  @Test
  public void testFindOneWithSort() {
    PersonWithAList p = new PersonWithAList();
    p.setFirstName("Sven");
    p.setAge(22);
    template.insert(p);

    PersonWithAList p2 = new PersonWithAList();
    p2.setFirstName("Erik");
    p2.setAge(21);
    template.insert(p2);

    PersonWithAList p3 = new PersonWithAList();
    p3.setFirstName("Mark");
    p3.setAge(40);
    template.insert(p3);

    // test query with a sort
    Query q2 = new Query(Criteria.where("age").gt(10));
    q2.sort().on("age", Order.DESCENDING);
    PersonWithAList p5 = template.findOne(q2, PersonWithAList.class);
    assertThat(p5.getFirstName(), is("Mark"));
  }
  private void testProperHandlingOfDifferentIdTypes(MongoTemplate mongoTemplate) throws Exception {

    // String id - generated
    PersonWithIdPropertyOfTypeString p1 = new PersonWithIdPropertyOfTypeString();
    p1.setFirstName("Sven_1");
    p1.setAge(22);
    // insert
    mongoTemplate.insert(p1);
    // also try save
    mongoTemplate.save(p1);
    assertThat(p1.getId(), notNullValue());
    PersonWithIdPropertyOfTypeString p1q =
        mongoTemplate.findOne(
            new Query(where("id").is(p1.getId())), PersonWithIdPropertyOfTypeString.class);
    assertThat(p1q, notNullValue());
    assertThat(p1q.getId(), is(p1.getId()));
    checkCollectionContents(PersonWithIdPropertyOfTypeString.class, 1);

    // String id - provided
    PersonWithIdPropertyOfTypeString p2 = new PersonWithIdPropertyOfTypeString();
    p2.setFirstName("Sven_2");
    p2.setAge(22);
    p2.setId("TWO");
    // insert
    mongoTemplate.insert(p2);
    // also try save
    mongoTemplate.save(p2);
    assertThat(p2.getId(), notNullValue());
    PersonWithIdPropertyOfTypeString p2q =
        mongoTemplate.findOne(
            new Query(where("id").is(p2.getId())), PersonWithIdPropertyOfTypeString.class);
    assertThat(p2q, notNullValue());
    assertThat(p2q.getId(), is(p2.getId()));
    checkCollectionContents(PersonWithIdPropertyOfTypeString.class, 2);

    // String _id - generated
    PersonWith_idPropertyOfTypeString p3 = new PersonWith_idPropertyOfTypeString();
    p3.setFirstName("Sven_3");
    p3.setAge(22);
    // insert
    mongoTemplate.insert(p3);
    // also try save
    mongoTemplate.save(p3);
    assertThat(p3.get_id(), notNullValue());
    PersonWith_idPropertyOfTypeString p3q =
        mongoTemplate.findOne(
            new Query(where("_id").is(p3.get_id())), PersonWith_idPropertyOfTypeString.class);
    assertThat(p3q, notNullValue());
    assertThat(p3q.get_id(), is(p3.get_id()));
    checkCollectionContents(PersonWith_idPropertyOfTypeString.class, 1);

    // String _id - provided
    PersonWith_idPropertyOfTypeString p4 = new PersonWith_idPropertyOfTypeString();
    p4.setFirstName("Sven_4");
    p4.setAge(22);
    p4.set_id("FOUR");
    // insert
    mongoTemplate.insert(p4);
    // also try save
    mongoTemplate.save(p4);
    assertThat(p4.get_id(), notNullValue());
    PersonWith_idPropertyOfTypeString p4q =
        mongoTemplate.findOne(
            new Query(where("_id").is(p4.get_id())), PersonWith_idPropertyOfTypeString.class);
    assertThat(p4q, notNullValue());
    assertThat(p4q.get_id(), is(p4.get_id()));
    checkCollectionContents(PersonWith_idPropertyOfTypeString.class, 2);

    // ObjectId id - generated
    PersonWithIdPropertyOfTypeObjectId p5 = new PersonWithIdPropertyOfTypeObjectId();
    p5.setFirstName("Sven_5");
    p5.setAge(22);
    // insert
    mongoTemplate.insert(p5);
    // also try save
    mongoTemplate.save(p5);
    assertThat(p5.getId(), notNullValue());
    PersonWithIdPropertyOfTypeObjectId p5q =
        mongoTemplate.findOne(
            new Query(where("id").is(p5.getId())), PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(p5q, notNullValue());
    assertThat(p5q.getId(), is(p5.getId()));
    checkCollectionContents(PersonWithIdPropertyOfTypeObjectId.class, 1);

    // ObjectId id - provided
    PersonWithIdPropertyOfTypeObjectId p6 = new PersonWithIdPropertyOfTypeObjectId();
    p6.setFirstName("Sven_6");
    p6.setAge(22);
    p6.setId(new ObjectId());
    // insert
    mongoTemplate.insert(p6);
    // also try save
    mongoTemplate.save(p6);
    assertThat(p6.getId(), notNullValue());
    PersonWithIdPropertyOfTypeObjectId p6q =
        mongoTemplate.findOne(
            new Query(where("id").is(p6.getId())), PersonWithIdPropertyOfTypeObjectId.class);
    assertThat(p6q, notNullValue());
    assertThat(p6q.getId(), is(p6.getId()));
    checkCollectionContents(PersonWithIdPropertyOfTypeObjectId.class, 2);

    // ObjectId _id - generated
    PersonWith_idPropertyOfTypeObjectId p7 = new PersonWith_idPropertyOfTypeObjectId();
    p7.setFirstName("Sven_7");
    p7.setAge(22);
    // insert
    mongoTemplate.insert(p7);
    // also try save
    mongoTemplate.save(p7);
    assertThat(p7.get_id(), notNullValue());
    PersonWith_idPropertyOfTypeObjectId p7q =
        mongoTemplate.findOne(
            new Query(where("_id").is(p7.get_id())), PersonWith_idPropertyOfTypeObjectId.class);
    assertThat(p7q, notNullValue());
    assertThat(p7q.get_id(), is(p7.get_id()));
    checkCollectionContents(PersonWith_idPropertyOfTypeObjectId.class, 1);

    // ObjectId _id - provided
    PersonWith_idPropertyOfTypeObjectId p8 = new PersonWith_idPropertyOfTypeObjectId();
    p8.setFirstName("Sven_8");
    p8.setAge(22);
    p8.set_id(new ObjectId());
    // insert
    mongoTemplate.insert(p8);
    // also try save
    mongoTemplate.save(p8);
    assertThat(p8.get_id(), notNullValue());
    PersonWith_idPropertyOfTypeObjectId p8q =
        mongoTemplate.findOne(
            new Query(where("_id").is(p8.get_id())), PersonWith_idPropertyOfTypeObjectId.class);
    assertThat(p8q, notNullValue());
    assertThat(p8q.get_id(), is(p8.get_id()));
    checkCollectionContents(PersonWith_idPropertyOfTypeObjectId.class, 2);

    // Integer id - provided
    PersonWithIdPropertyOfTypeInteger p9 = new PersonWithIdPropertyOfTypeInteger();
    p9.setFirstName("Sven_9");
    p9.setAge(22);
    p9.setId(Integer.valueOf(12345));
    // insert
    mongoTemplate.insert(p9);
    // also try save
    mongoTemplate.save(p9);
    assertThat(p9.getId(), notNullValue());
    PersonWithIdPropertyOfTypeInteger p9q =
        mongoTemplate.findOne(
            new Query(where("id").in(p9.getId())), PersonWithIdPropertyOfTypeInteger.class);
    assertThat(p9q, notNullValue());
    assertThat(p9q.getId(), is(p9.getId()));
    checkCollectionContents(PersonWithIdPropertyOfTypeInteger.class, 1);

    // int id - provided
    PersonWithIdPropertyOfPrimitiveInt p10 = new PersonWithIdPropertyOfPrimitiveInt();
    p10.setFirstName("Sven_10");
    p10.setAge(22);
    p10.setId(12345);
    // insert
    mongoTemplate.insert(p10);
    // also try save
    mongoTemplate.save(p10);
    assertThat(p10.getId(), notNullValue());
    PersonWithIdPropertyOfPrimitiveInt p10q =
        mongoTemplate.findOne(
            new Query(where("id").in(p10.getId())), PersonWithIdPropertyOfPrimitiveInt.class);
    assertThat(p10q, notNullValue());
    assertThat(p10q.getId(), is(p10.getId()));
    checkCollectionContents(PersonWithIdPropertyOfPrimitiveInt.class, 1);

    // Long id - provided
    PersonWithIdPropertyOfTypeLong p11 = new PersonWithIdPropertyOfTypeLong();
    p11.setFirstName("Sven_9");
    p11.setAge(22);
    p11.setId(Long.valueOf(12345L));
    // insert
    mongoTemplate.insert(p11);
    // also try save
    mongoTemplate.save(p11);
    assertThat(p11.getId(), notNullValue());
    PersonWithIdPropertyOfTypeLong p11q =
        mongoTemplate.findOne(
            new Query(where("id").in(p11.getId())), PersonWithIdPropertyOfTypeLong.class);
    assertThat(p11q, notNullValue());
    assertThat(p11q.getId(), is(p11.getId()));
    checkCollectionContents(PersonWithIdPropertyOfTypeLong.class, 1);

    // long id - provided
    PersonWithIdPropertyOfPrimitiveLong p12 = new PersonWithIdPropertyOfPrimitiveLong();
    p12.setFirstName("Sven_10");
    p12.setAge(22);
    p12.setId(12345L);
    // insert
    mongoTemplate.insert(p12);
    // also try save
    mongoTemplate.save(p12);
    assertThat(p12.getId(), notNullValue());
    PersonWithIdPropertyOfPrimitiveLong p12q =
        mongoTemplate.findOne(
            new Query(where("id").in(p12.getId())), PersonWithIdPropertyOfPrimitiveLong.class);
    assertThat(p12q, notNullValue());
    assertThat(p12q.getId(), is(p12.getId()));
    checkCollectionContents(PersonWithIdPropertyOfPrimitiveLong.class, 1);
  }
  private static void assertTagCount(String tag, int n, TagCount tagCount) {

    assertThat(tagCount.getTag(), is(tag));
    assertThat(tagCount.getN(), is(n));
  }
 private void checkCollectionContents(Class<?> entityClass, int count) {
   assertThat(template.findAll(entityClass).size(), is(count));
 }