David Carr avatar David Carr committed 9635bc1

api: add overloads of match and group to support common builders

Comments (0)

Files changed (6)

 look like this:
 
     :::groovy
-    def cmdBody = new BasicDBObject([aggregate: 'DemoProduct', pipeline: [
+    def output = collection.aggregate(
             new BasicDBObject('$match', new BasicDBObject('_id.demoId': new ObjectId(demoId))),
             new BasicDBObject('$unwind', '$attributes'),
             new BasicDBObject('$match', new BasicDBObject('attributes.id', attributeId)),
             new BasicDBObject('$group', new BasicDBObject('_id', '$attributes.value'))
-    ]])
-    def response = mongoDb.command(cmdBody)
+    )
 
 Using the extension, it would look more like this:
 
     :::groovy
-    def cmdBody = ( AggregateBuilder.aggregate('DemoProduct')
+    def output = ( AggregateBuilder.aggregate(collection)
             .match('_id.demoId', new ObjectId(demoId))
             .unwind('$attributes')
             .match('attributes.id', attributeId)
             .group('_id', '$attributes.value')
-            .get()
+            .run()
     )
-    def response = mongoDb.command(cmdBody)
 
 [1]: http://www.mongodb.org/display/DOCS/Java+Language+Center
 [2]: http://docs.mongodb.org/manual/applications/aggregation/
      * Add AggregateBuilder.run() method using aggregate driver helper method
      * Fix "No target field for operand" error using GroupBuilder.start(...)
      * GroupOperators and PipelineOperators are now package-private
+     * Add overloads to AggregateBuilder match and group methods to support
+       common builders
 
  * 0.1.0 (Released 8-12-2012)
      * Initial release

src/main/java/org/bitbucket/davidm24/mongodb/aggregate/AggregateBuilder.java

 import com.mongodb.BasicDBObject;
 import com.mongodb.DBCollection;
 import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
 
 /**
  * Utility for running aggregate commands.
     public DBObject get() {
         return _command;
     }
+    
+    /**
+     * Adds a {@code $group} operator for the specified builder to the pipeline.
+     * 
+     * <p>This operator groups documents together for the purpose of calculating
+     * aggregate values based on a collection of documents. Practically, group
+     * often supports tasks such as average page views for each page in a
+     * website on a daily basis.</p>
+     * 
+     * @param builder a builder specifying how to group
+     * @return the AggregateBuilder instance for call chaining
+     * @since 0.1.1
+     */
+    public AggregateBuilder group(GroupBuilder builder) {
+        return group(builder.get());
+    }
 
     /**
      * Adds a {@code $group} operator for the specified object to the pipeline.
      * @since 0.1.0
      */
     public AggregateBuilder group(Object object) {
-        // TODO: add a specialized overload for GroupBuilder
         addOperand(PipelineOperators.GROUP, object);
         return this;
     }
      * @param value the value for the document
      * @return the AggregateBuilder instance for call chaining
      * @since 0.1.0
+     * @deprecated use {@link #group(GroupBuilder)} instead
      */
+    @Deprecated
     public AggregateBuilder group(String key, Object value) {
-        // TODO: determine if this signature makes sense
         return group(new BasicDBObject(key, value));
     }
 
         addOperand(PipelineOperators.LIMIT, count);
         return this;
     }
+    
+    /**
+     * Adds a {@code $match} operator for the specified builder to the pipeline.
+     * 
+     * <p>This operator provides a query-like interface to filter documents out
+     * of the aggregation pipeline. The {@code $match} drops documents that do
+     * not match the condition from the aggregation pipeline, and it passes
+     * documents that match along the pipeline unaltered.  The syntax passed to
+     * this operator is identical to the query syntax.</p>
+     * 
+     * @param object a builder for the query on which to match
+     * @return the AggregateBuilder instance for call chaining
+     * @since 0.1.1
+     */
+    public AggregateBuilder match(QueryBuilder builder) {
+        return match(builder.get());
+    }
 
     /**
      * Adds a {@code $match} operator for the specified object to the pipeline.
      * @since 0.1.0
      */
     public AggregateBuilder match(Object object) {
-        // TODO: add a specialized overload for QueryBuilder
         addOperand(PipelineOperators.MATCH, object);
         return this;
     }
      * Adds a {@code $match} operator for the specified key/value pair.  The
      * arguments will be treated as a single-key document.  This is intended
      * only as a convenience for simple single-key, direct equality match
-     * clauses. For more complicated uses, use {@link #match(Object)}.
+     * clauses. For more complicated uses, use {@link #match(QueryBuilder)}.
      * 
      * <p>This operator provides a query-like interface to filter documents out
      * of the aggregation pipeline. The {@code $match} drops documents that do

src/main/java/org/bitbucket/davidm24/mongodb/aggregate/GroupBuilder.java

  * In general usage, you start a new group pipeline with {@link #start}. You
  * then call {@link #put} to specify a target field, followed by a group
  * aggregation function to specify how to populate that field. Repeat this for
- * each target field, and then call {@link #get} to retrieve the pipeline
- * operation as a {@link DBObject} suitable for passing to
- * {@link AggregateBuilder#group}.
+ * each target field, and then [pass it to {@link AggregateBuilder#group} add it
+ * to the pipeline.
  * </p>
  * 
  * <p>For example, consider the following JavaScript example, converted to Java:
  * GroupBuilder.start()
  *    .put("_id").to("$author")
  *    .put("docsPerAuthor").sum(1)
- *    .put("viewsPerAuthor").sum("$pageViews")
- *    .get()</pre>
+ *    .put("viewsPerAuthor").sum("$pageViews")</pre>
  * </p>
  * 
  * @author David M. Carr

src/main/java/org/bitbucket/davidm24/mongodb/aggregate/package-info.java

         .group(GroupBuilder.start()
                  .put("_id").to(newMap("state", "$state", "city", "$city"))
                  .put("pop").sum("$pop")
-                 .get()
         )
         .sort(newMap("pop", 1))
         .group(GroupBuilder.start()
                 .put("biggestPop").last("$pop")
                 .put("smallestCity").first("$_id.city")
                 .put("smallestPop").first("$pop")
-                .get()
         )
         .project(newMap(
                 "_id", 0,

src/test/java/org/bitbucket/davidm24/mongodb/aggregate/AggregateBuilderIT.java

     public void aggregateByCollectionNameAndGetTest() {
         String testName = "aggregateByCollectionNameAndGetTest";
         DBObject cmdBody = AggregateBuilder.aggregate(testName).group(
-                GroupBuilder.start().put("_id").sum("$val").get()
+                GroupBuilder.start().put("_id").sum("$val")
                 ).get();
         assertCommandStructureFromResource(
                 testName + ".expected.command.json", cmdBody);
                 .group(GroupBuilder.start()
                         .put("_id").to(new BasicDBObject("tags", "$tags"))
                         .put("authors").addToSet("$author")
-                        .get()
                 )
                 .run();
         verifyAggregationOutputFromResources(testName, output);
         AggregationOutput output = AggregateBuilder
                 .aggregate(collection)
                 .match(QueryBuilder.start("score").greaterThan(50)
-                        .lessThanEquals(90).get())
+                        .lessThanEquals(90))
                 .run();
         verifyAggregationOutputFromResources(testName, output);
     }
                         .put("_id").to("$author")
                         .put("docsPerAuthor").sum(1)
                         .put("viewsPerAuthor").sum("$pageViews")
-                        .get()
                 )
                 .sort(newMap("_id", 1)) // ensure the results are in a
                                         // predictable order
                         .to(newMap("author", "$author", "title", "$title"))
                         .put("docsPerAuthor").sum(1)
                         .put("viewsPerAuthor").sum("$pageViews")
-                        .get()
                 )
                 .sort(newMap("_id", 1)) // ensure the results are in a
                                         // predictable order

src/test/java/org/bitbucket/davidm24/mongodb/aggregate/DocumentationExamplesIT.java

                 .group(GroupBuilder.start()
                         .put("_id").to("$state")
                         .put("totalPop").sum("$pop")
-                        .get()
                 )
                 .match(QueryBuilder.start()
                         .put("totalPop").greaterThanEquals(10 * 1000 * 1000)
                         .put("_id")
                         .to(newMap("state", "$state", "city", "$city"))
                         .put("pop").sum("$pop")
-                        .get()
                 )
                 .group(GroupBuilder.start()
                         .put("_id").to("$_id.state")
                         .put("avgCityPop").avg("$pop")
-                        .get()
                 )
                 // Not part of the example, but important for reproducibility
                 .sort(newMap("_id", 1))
                         .put("_id")
                         .to(newMap("state", "$state", "city", "$city"))
                         .put("pop").sum("$pop")
-                        .get()
                 )
                 // Not quite what was in the documentation, since it was
                 // non-deterministic (dataset contains cities tied for pop)
                         .put("biggestPop").last("$pop")
                         .put("smallestCity").first("$_id.city")
                         .put("smallestPop").first("$pop")
-                        .get()
                 )
                 .project(
                         newMap(
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.