Skip to content

Commit ba9ff84

Browse files
committed
JAVA-630: Implemented elemMatch and not operators.
Added more constants to QueryOperators to prepare for the rest of the operators
1 parent 08f5aa3 commit ba9ff84

File tree

3 files changed

+178
-54
lines changed

3 files changed

+178
-54
lines changed

src/main/com/mongodb/QueryBuilder.java

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
package com.mongodb;
2424

2525
import java.util.ArrayList;
26+
import java.util.Collections;
2627
import java.util.List;
2728
import java.util.regex.Pattern;
2829

@@ -32,7 +33,7 @@
3233
*
3334
*/
3435
public class QueryBuilder {
35-
36+
3637
/**
3738
* Creates a builder with an empty query
3839
*/
@@ -61,7 +62,7 @@ public static QueryBuilder start(String key) {
6162
* Adds a new key to the query if not present yet.
6263
* Sets this key as the current key.
6364
* @param key MongoDB document key
64-
* @return Returns the current QueryBuilder
65+
* @return this
6566
*/
6667
public QueryBuilder put(String key) {
6768
_currentKey = key;
@@ -72,10 +73,10 @@ public QueryBuilder put(String key) {
7273
}
7374

7475
/**
75-
* Equivalent to <code>QueryBuilder.put(key)</code>. Intended for compound query chains to be more readable
76-
* Example: QueryBuilder.start("a").greaterThan(1).and("b").lessThan(3)
76+
* Equivalent to <code>QueryBuilder.put(key)</code>. Intended for compound query chains to be more readable, e.g.
77+
* {@code QueryBuilder.start("a").greaterThan(1).and("b").lessThan(3) }
7778
* @param key MongoDB document key
78-
* @return Returns the current QueryBuilder with an appended key operand
79+
* @return this
7980
*/
8081
public QueryBuilder and(String key) {
8182
return put(key);
@@ -210,7 +211,19 @@ public QueryBuilder regex(Pattern regex) {
210211
addOperand(null, regex);
211212
return this;
212213
}
213-
214+
215+
/**
216+
* Equivalent to the $elemMatch operand
217+
* @param match the object to match
218+
* @return Returns the current QueryBuilder with an appended elemMatch operator
219+
*/
220+
public QueryBuilder elemMatch(final DBObject match) {
221+
addOperand(QueryOperators.ELEM_MATCH, match);
222+
return this;
223+
}
224+
225+
226+
214227
/**
215228
* Equivalent of the $within operand, used for geospatial operation
216229
* @param x x coordinate
@@ -219,8 +232,8 @@ public QueryBuilder regex(Pattern regex) {
219232
* @return
220233
*/
221234
public QueryBuilder withinCenter( double x , double y , double radius ){
222-
addOperand( "$within" ,
223-
new BasicDBObject( "$center" , new Object[]{ new Double[]{ x , y } , radius } ) );
235+
addOperand( QueryOperators.WITHIN ,
236+
new BasicDBObject(QueryOperators.CENTER, new Object[]{ new Double[]{ x , y } , radius } ) );
224237
return this;
225238
}
226239

@@ -231,7 +244,7 @@ public QueryBuilder withinCenter( double x , double y , double radius ){
231244
* @return
232245
*/
233246
public QueryBuilder near( double x , double y ){
234-
addOperand( "$near" ,
247+
addOperand(QueryOperators.NEAR,
235248
new Double[]{ x , y } );
236249
return this;
237250
}
@@ -244,7 +257,7 @@ public QueryBuilder near( double x , double y ){
244257
* @return
245258
*/
246259
public QueryBuilder near( double x , double y , double maxDistance ){
247-
addOperand( "$near" ,
260+
addOperand( QueryOperators.NEAR ,
248261
new Double[]{ x , y , maxDistance } );
249262
return this;
250263
}
@@ -256,7 +269,7 @@ public QueryBuilder near( double x , double y , double maxDistance ){
256269
* @return
257270
*/
258271
public QueryBuilder nearSphere( double longitude , double latitude ){
259-
addOperand( "$nearSphere" ,
272+
addOperand(QueryOperators.NEAR_SPHERE,
260273
new Double[]{ longitude , latitude } );
261274
return this;
262275
}
@@ -269,7 +282,7 @@ public QueryBuilder nearSphere( double longitude , double latitude ){
269282
* @return
270283
*/
271284
public QueryBuilder nearSphere( double longitude , double latitude , double maxDistance ){
272-
addOperand( "$nearSphere" ,
285+
addOperand( QueryOperators.NEAR_SPHERE ,
273286
new Double[]{ longitude , latitude , maxDistance } );
274287
return this;
275288
}
@@ -283,8 +296,8 @@ public QueryBuilder nearSphere( double longitude , double latitude , double maxD
283296
* @return
284297
*/
285298
public QueryBuilder withinCenterSphere( double longitude , double latitude , double maxDistance ){
286-
addOperand( "$within" ,
287-
new BasicDBObject( "$centerSphere" , new Object[]{ new Double[]{longitude , latitude} , maxDistance } ) );
299+
addOperand( QueryOperators.WITHIN ,
300+
new BasicDBObject(QueryOperators.CENTER_SPHERE, new Object[]{ new Double[]{longitude , latitude} , maxDistance } ) );
288301
return this;
289302
}
290303

@@ -298,56 +311,65 @@ public QueryBuilder withinCenterSphere( double longitude , double latitude , dou
298311
* @return
299312
*/
300313
public QueryBuilder withinBox(double x, double y, double x2, double y2) {
301-
addOperand( "$within" ,
302-
new BasicDBObject( "$box" , new Object[] { new Double[] { x, y }, new Double[] { x2, y2 } } ) );
314+
addOperand( QueryOperators.WITHIN ,
315+
new BasicDBObject(QueryOperators.BOX, new Object[] { new Double[] { x, y }, new Double[] { x2, y2 } } ) );
303316
return this;
304317
}
305318

306319
/**
307320
* Equivalent to a $within operand, based on a bounding polygon represented by an array of points
308321
*
309322
* @param points an array of Double[] defining the vertices of the search area
310-
* @return
323+
* @return this
311324
*/
312325
public QueryBuilder withinPolygon(List<Double[]> points) {
313326
if(points == null || points.isEmpty() || points.size() < 3)
314327
throw new IllegalArgumentException("Polygon insufficient number of vertices defined");
315-
addOperand( "$within" ,
316-
new BasicDBObject( "$polygon" , points ) );
328+
addOperand( QueryOperators.WITHIN ,
329+
new BasicDBObject(QueryOperators.POLYGON, points ) );
317330
return this;
318331
}
319332

320333
/**
321-
* Equivalent to a $or operand
322-
* @param ors
323-
* @return
334+
* Equivalent to $not meta operator. Must be followed by an operand, not a value, e.g.
335+
* {@code QueryBuilder.start("val").not().mod(Arrays.asList(10, 1)) }
336+
*
337+
* @return Returns the current QueryBuilder with an appended "not" meta operator
338+
*/
339+
public QueryBuilder not() {
340+
_hasNot = true;
341+
return this;
342+
}
343+
344+
/**
345+
* Equivalent to an $or operand
346+
* @param ors the list of conditions to or together
347+
* @return Returns the current QueryBuilder with appended "or" operator
324348
*/
325349
@SuppressWarnings("unchecked")
326350
public QueryBuilder or( DBObject ... ors ){
327-
List l = (List)_query.get( "$or" );
351+
List l = (List)_query.get( QueryOperators.OR );
328352
if ( l == null ){
329353
l = new ArrayList();
330-
_query.put( "$or" , l );
354+
_query.put( QueryOperators.OR , l );
331355
}
332-
for ( DBObject o : ors )
333-
l.add( o );
356+
Collections.addAll(l, ors);
334357
return this;
335358
}
336359

337360
/**
338361
* Equivalent to an $and operand
339-
* @param ands
340-
* @return
362+
* @param ands the list of conditions to and together
363+
* @return Returns the current QueryBuilder with appended "and" operator
341364
*/
342365
@SuppressWarnings("unchecked")
343366
public QueryBuilder and( DBObject ... ands ){
344-
List l = (List)_query.get( "$and" );
367+
List l = (List)_query.get( QueryOperators.AND );
345368
if ( l == null ){
346369
l = new ArrayList();
347-
_query.put( "$and" , l );
370+
_query.put( QueryOperators.AND , l );
348371
}
349-
for ( DBObject o : ands )
350-
l.add( o );
372+
Collections.addAll(l, ands);
351373
return this;
352374
}
353375

@@ -367,6 +389,10 @@ public DBObject get() {
367389

368390
private void addOperand(String op, Object value) {
369391
if(op == null) {
392+
if (_hasNot) {
393+
value = new BasicDBObject(QueryOperators.NOT, value);
394+
_hasNot = false;
395+
}
370396
_query.put(_currentKey, value);
371397
return;
372398
}
@@ -375,13 +401,21 @@ private void addOperand(String op, Object value) {
375401
BasicDBObject operand;
376402
if(!(storedValue instanceof DBObject)) {
377403
operand = new BasicDBObject();
378-
_query.put(_currentKey, operand);
404+
if (_hasNot) {
405+
DBObject notOperand = new BasicDBObject(QueryOperators.NOT, operand);
406+
_query.put(_currentKey, notOperand);
407+
_hasNot = false;
408+
} else {
409+
_query.put(_currentKey, operand);
410+
}
379411
} else {
380412
operand = (BasicDBObject)_query.get(_currentKey);
413+
if (operand.get(QueryOperators.NOT) != null) {
414+
operand = (BasicDBObject) operand.get(QueryOperators.NOT);
415+
}
381416
}
382417
operand.put(op, value);
383418
}
384-
385419
@SuppressWarnings("serial")
386420
static class QueryBuilderException extends RuntimeException {
387421
QueryBuilderException(String message) {
@@ -392,5 +426,6 @@ private static class NullObject {}
392426

393427
private DBObject _query;
394428
private String _currentKey;
429+
private boolean _hasNot;
395430

396431
}

src/main/com/mongodb/QueryOperators.java

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,55 @@
1919

2020
/**
2121
* MongoDB keywords for various query operations
22-
* @author Julson Lim
2322
*
23+
* @author Julson Lim
2424
*/
2525
public class QueryOperators {
26-
public static final String GT = "$gt";
27-
public static final String GTE = "$gte";
28-
public static final String LT = "$lt";
29-
public static final String LTE = "$lte";
30-
public static final String NE = "$ne";
31-
public static final String IN = "$in";
32-
public static final String NIN = "$nin";
33-
public static final String MOD = "$mod";
34-
public static final String ALL = "$all";
35-
public static final String SIZE = "$size";
36-
public static final String EXISTS = "$exists";
37-
public static final String WHERE = "$where";
38-
public static final String NEAR = "$near";
26+
public static final String OR = "$or";
27+
public static final String AND = "$and";
28+
29+
public static final String GT = "$gt";
30+
public static final String GTE = "$gte";
31+
public static final String LT = "$lt";
32+
public static final String LTE = "$lte";
33+
34+
public static final String NE = "$ne";
35+
public static final String IN = "$in";
36+
public static final String NIN = "$nin";
37+
public static final String MOD = "$mod";
38+
public static final String ALL = "$all";
39+
public static final String SIZE = "$size";
40+
public static final String EXISTS = "$exists";
41+
public static final String ELEM_MATCH = "$elemMatch";
42+
43+
// (to be implemented in QueryBuilder)
44+
public static final String WHERE = "$where";
45+
public static final String NOR = "$nor";
46+
public static final String TYPE = "$type";
47+
public static final String NOT = "$not";
48+
49+
// geo operators
50+
public static final String WITHIN = "$within";
51+
public static final String NEAR = "$near";
52+
public static final String NEAR_SPHERE = "$nearSphere";
53+
public static final String BOX = "$box";
54+
public static final String CENTER = "$center";
55+
public static final String POLYGON = "$polygon";
56+
public static final String CENTER_SPHERE = "$centerSphere";
57+
// (to be implemented in QueryBuilder)
58+
public static final String MAX_DISTANCE = "$maxDistance";
59+
public static final String UNIQUE_DOCS = "$uniqueDocs";
60+
61+
62+
// meta query operators (to be implemented in QueryBuilder)
63+
public static final String RETURN_KEY = "$returnKey";
64+
public static final String MAX_SCAN = "$maxScan";
65+
public static final String ORDER_BY = "$orderby";
66+
public static final String EXPLAIN = "$explain";
67+
public static final String SNAPSHOT = "$snapshot";
68+
public static final String MIN = "$min";
69+
public static final String MAX = "$max";
70+
public static final String SHOW_DISK_LOC = "$showDiskLoc";
71+
public static final String HINT = "$hint";
72+
public static final String COMMENT = "$comment";
3973
}

0 commit comments

Comments
 (0)