diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java index 6c8f4aa67..d8dacc666 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2011 the original author or authors. + * Copyright 2010-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +17,25 @@ package org.springframework.data.mongodb.core.query; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; + +import org.springframework.util.Assert; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; +/** + * @author Thomas Risberg + * @author Oliver Gierke + * @author Patryk Wasik + */ public class Field { - private Map criteria = new HashMap(); - - private Map slices = new HashMap(); + private final Map criteria = new HashMap(); + private final Map slices = new HashMap(); + private final Map elemMatchs = new HashMap(); + private String postionKey; + private int positionValue; public Field include(String key) { criteria.put(key, Integer.valueOf(1)); @@ -47,14 +57,50 @@ public class Field { return this; } + public Field elemMatch(String key, Criteria elemMatchCriteria) { + elemMatchs.put(key, elemMatchCriteria); + return this; + } + + /** + * The array field must appear in the query. Only one positional {@code $} operator can appear in the projection and + * only one array field can appear in the query. + * + * @param field query array field, must not be {@literal null} or empty. + * @param value + * @return + */ + public Field position(String field, int value) { + + Assert.hasText(field, "Field must not be null or empty!"); + + postionKey = field; + positionValue = value; + + return this; + } + public DBObject getFieldsObject() { + DBObject dbo = new BasicDBObject(); + for (String k : criteria.keySet()) { - dbo.put(k, (criteria.get(k))); + dbo.put(k, criteria.get(k)); } + for (String k : slices.keySet()) { - dbo.put(k, new BasicDBObject("$slice", (slices.get(k)))); + dbo.put(k, new BasicDBObject("$slice", slices.get(k))); } + + for (Entry entry : elemMatchs.entrySet()) { + DBObject dbObject = new BasicDBObject("$elemMatch", entry.getValue().getCriteriaObject()); + dbo.put(entry.getKey(), dbObject); + } + + if (postionKey != null) { + dbo.put(postionKey + ".$", positionValue); + } + return dbo; } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java index 41f02f0a9..f7415bbc2 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java @@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.query; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.springframework.data.mongodb.core.query.Criteria.*; +import static org.springframework.data.mongodb.core.query.Query.*; import org.junit.Assert; import org.junit.Rule; @@ -32,6 +33,7 @@ import org.springframework.data.mongodb.InvalidMongoDbApiUsageException; * * @author Thomas Risberg * @author Oliver Gierke + * @author Patryk Wasik */ public class QueryTests { @@ -104,6 +106,21 @@ public class QueryTests { Assert.assertEquals(expectedFields, q.getFieldsObject().toString()); } + /** + * @see DATAMONGO-652 + */ + @Test + public void testQueryWithFieldsElemMatchAndPositionalOperator() { + + Query query = query(where("name").gte("M").lte("T").and("age").not().gt(22)); + query.fields().elemMatch("products", where("name").is("milk")).position("comments", 2); + + String expected = "{ \"name\" : { \"$gte\" : \"M\" , \"$lte\" : \"T\"} , \"age\" : { \"$not\" : { \"$gt\" : 22}}}"; + assertThat(query.getQueryObject().toString(), is(expected)); + String expectedFields = "{ \"products\" : { \"$elemMatch\" : { \"name\" : \"milk\"}} , \"comments.$\" : 2}"; + assertThat(query.getFieldsObject().toString(), is(expectedFields)); + } + @Test public void testSimpleQueryWithChainedCriteria() { Query q = new Query(where("name").is("Thomas").and("age").lt(80));