Skip to content

Commit 83fef69

Browse files
author
Steve Briskin
committed
JAVA-563: added orderby to findOne(). Refactored query construction to be consistent between find() and findOne().
1 parent be5a807 commit 83fef69

4 files changed

Lines changed: 212 additions & 35 deletions

File tree

src/main/com/mongodb/DBCollection.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ public DBObject findOne()
658658
*/
659659
public DBObject findOne( DBObject o )
660660
throws MongoException {
661-
return findOne( o, null, getReadPreference());
661+
return findOne( o, null, null, getReadPreference());
662662
}
663663

664664
/**
@@ -669,8 +669,21 @@ public DBObject findOne( DBObject o )
669669
* @dochub find
670670
*/
671671
public DBObject findOne( DBObject o, DBObject fields ) {
672-
return findOne( o, fields, getReadPreference());
672+
return findOne( o, fields, null, getReadPreference());
673673
}
674+
675+
/**
676+
* Returns a single obejct from this collection matching the query.
677+
* @param o the query object
678+
* @param fields fields to return
679+
* @param orderby fields to order by
680+
* @return the object found, or <code>null</code> if no such object exists
681+
* @dochub find
682+
*/
683+
public DBObject findOne( DBObject o, DBObject fields, DBObject orderby){
684+
return findOne(o, fields, orderby, getReadPreference());
685+
}
686+
674687
/**
675688
* Returns a single object from this collection matching the query.
676689
* @param o the query object
@@ -679,7 +692,26 @@ public DBObject findOne( DBObject o, DBObject fields ) {
679692
* @dochub find
680693
*/
681694
public DBObject findOne( DBObject o, DBObject fields, ReadPreference readPref ) {
682-
Iterator<DBObject> i = __find( o , fields , 0 , -1 , 0, getOptions(), readPref, getDecoder() );
695+
return findOne(o, fields, null, readPref);
696+
}
697+
698+
/**
699+
* Returns a single object from this collection matching the query.
700+
* @param o the query object
701+
* @param fields fields to return
702+
* @param orderby fields to order by
703+
* @return the object found, or <code>null</code> if no such object exists
704+
* @dochub find
705+
*/
706+
public DBObject findOne( DBObject o, DBObject fields, DBObject orderby, ReadPreference readPref ) {
707+
708+
DBObject queryop = new QueryOpBuilder()
709+
.addQuery(o)
710+
.addOrderBy(orderby)
711+
.get();
712+
713+
Iterator<DBObject> i = __find( queryop, fields , 0 , -1 , 0, getOptions(), readPref, getDecoder() );
714+
683715
DBObject obj = (i.hasNext() ? i.next() : null);
684716
if ( obj != null && ( fields != null && fields.keySet().size() > 0 ) ){
685717
obj.markAsPartialObject();

src/main/com/mongodb/DBCursor.java

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.*;
2323

2424
import com.mongodb.DBApiLayer.Result;
25+
import com.mongodb.QueryOpBuilder;
2526

2627

2728
/** An iterator over database results.
@@ -351,25 +352,27 @@ private void _check()
351352

352353
DBObject foo = _query;
353354
if (hasSpecialQueryFields()) {
354-
foo = _specialFields == null ? new BasicDBObject() : _specialFields;
355-
356-
_addToQueryObject(foo, "query", _query, true);
357-
_addToQueryObject(foo, "orderby", _orderBy, false);
358-
if (_hint != null)
359-
_addToQueryObject(foo, "$hint", _hint);
360-
if (_hintDBObj != null)
361-
_addToQueryObject(foo, "$hint", _hintDBObj);
362-
363-
if (_explain)
364-
foo.put("$explain", true);
365-
if (_snapshot)
366-
foo.put("$snapshot", true);
355+
QueryOpBuilder opbuilder = (_specialFields == null ? new QueryOpBuilder() : new QueryOpBuilder(_specialFields));
356+
357+
opbuilder.addQuery(_query)
358+
.addOrderBy(_orderBy)
359+
.addHint(_hint)
360+
.addHint(_hintDBObj);
361+
362+
if(_explain)
363+
opbuilder.addExplain();
364+
if(_snapshot)
365+
opbuilder.addSnapshot();
366+
367+
foo = opbuilder.get();
367368
}
368369

369370
_it = _collection.__find(foo, _keysWanted, _skip, _batchSize, _limit, _options, _readPref, getDecoder());
370371
}
371372

372-
// Only create a new decoder if there is a decoder factory explicitly set on the collection. Otherwise return null
373+
374+
375+
// Only create a new decoder if there is a decoder factory explicitly set on the collection. Otherwise return null
373376
// so that the collection can use a cached decoder
374377
private DBDecoder getDecoder() {
375378
return _decoderFact != null ? _decoderFact.create() : null;
@@ -413,24 +416,6 @@ boolean hasSpecialQueryFields(){
413416
return _explain;
414417
}
415418

416-
void _addToQueryObject( DBObject query , String field , DBObject thing , boolean sendEmpty ){
417-
if ( thing == null )
418-
return;
419-
420-
if ( ! sendEmpty && thing.keySet().size() == 0 )
421-
return;
422-
423-
_addToQueryObject( query , field , thing );
424-
}
425-
426-
void _addToQueryObject( DBObject query , String field , Object thing ){
427-
428-
if ( thing == null )
429-
return;
430-
431-
query.put( field , thing );
432-
}
433-
434419
void _checkType( CursorType type ){
435420
if ( _cursorType == null ){
436421
_cursorType = type;
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package com.mongodb;
2+
3+
import com.mongodb.BasicDBObject;
4+
import com.mongodb.DBObject;
5+
6+
7+
/**
8+
* Utility for constructing Query operation command with query, orderby, hint, explain, snapshot
9+
*/
10+
public class QueryOpBuilder {
11+
private DBObject queryop;
12+
13+
/**
14+
* Creates a builder with an empty query op
15+
*/
16+
public QueryOpBuilder(){
17+
queryop = new BasicDBObject();
18+
}
19+
20+
/**
21+
* Creates a new builder
22+
* @param queryop
23+
*/
24+
public QueryOpBuilder(DBObject queryop){
25+
this.queryop = queryop;
26+
}
27+
28+
/**
29+
* Adds the query clause to the operation
30+
* @param query
31+
* @return
32+
*/
33+
public QueryOpBuilder addQuery(DBObject query){
34+
return addToQueryObject("query", query, true);
35+
}
36+
37+
/**
38+
* Adds the groupby clause to the operation
39+
* @param orderBy
40+
* @return
41+
*/
42+
public QueryOpBuilder addOrderBy(DBObject orderBy){
43+
return addToQueryObject("orderby", orderBy, false);
44+
}
45+
46+
/**
47+
* Adds the hint clause to the operation
48+
* @param hint
49+
* @return
50+
*/
51+
public QueryOpBuilder addHint(String hint){
52+
if(hint != null)
53+
addToQueryObject("$hint", hint);
54+
55+
return this;
56+
}
57+
58+
public QueryOpBuilder addHint(DBObject hint){
59+
if(hint != null)
60+
addToQueryObject("$hint", hint, false);
61+
62+
return this;
63+
}
64+
65+
/**
66+
* Adds the explain flag to the operation
67+
* @return
68+
*/
69+
public QueryOpBuilder addExplain(){
70+
return addToQueryObject("$explain", true);
71+
}
72+
73+
/**
74+
* Adds the snapshot flag to the operation
75+
* @return
76+
*/
77+
public QueryOpBuilder addSnapshot(){
78+
return addToQueryObject("$snapshot", true);
79+
80+
}
81+
82+
/**
83+
* Adds DBObject to the operation
84+
* @param field name of the field
85+
* @param obj object to add to the operation. Ignore if <code>null</code>.
86+
* @param sendEmpty if <code>true</code> adds obj even if it's empty. Ignore if <code>false</code> and obj is empty.
87+
* @return
88+
*/
89+
public QueryOpBuilder addToQueryObject(String field, DBObject obj, boolean sendEmpty) {
90+
if (obj == null)
91+
return this;
92+
93+
if (!sendEmpty && obj.keySet().size() == 0)
94+
return this;
95+
96+
return addToQueryObject(field, obj);
97+
}
98+
99+
/**
100+
* Adds an Object to the operation
101+
* @param field name of the field
102+
* @param obj Object to be added. Ignore if <code>null</code>
103+
* @return
104+
*/
105+
public QueryOpBuilder addToQueryObject(String field, Object obj) {
106+
107+
if (obj == null)
108+
return this;
109+
110+
queryop.put(field, obj);
111+
112+
return this;
113+
}
114+
115+
/**
116+
* gets the constructed query operation object
117+
* @return
118+
*/
119+
public DBObject get(){
120+
return queryop;
121+
}
122+
123+
}

src/test/com/mongodb/DBCollectionTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,43 @@ public void testFindOne() {
106106
assertEquals(obj.containsField("x"), false);
107107
assertEquals(obj.get("y"), 2);
108108
}
109+
110+
@Test
111+
public void testFindOneSort(){
112+
113+
DBCollection c = _db.getCollection("test");
114+
c.drop();
115+
116+
DBObject obj = c.findOne();
117+
assertEquals(obj, null);
118+
119+
c.insert(BasicDBObjectBuilder.start().add("_id", 1).add("x", 100).add("y", "abc").get());
120+
c.insert(BasicDBObjectBuilder.start().add("_id", 2).add("x", 200).add("y", "abc").get()); //max x
121+
c.insert(BasicDBObjectBuilder.start().add("_id", 3).add("x", 1).add("y", "abc").get());
122+
c.insert(BasicDBObjectBuilder.start().add("_id", 4).add("x", -100).add("y", "xyz").get()); //min x
123+
c.insert(BasicDBObjectBuilder.start().add("_id", 5).add("x", -50).add("y", "zzz").get()); //max y
124+
c.insert(BasicDBObjectBuilder.start().add("_id", 6).add("x", 9).add("y", "aaa").get()); //min y
125+
c.insert(BasicDBObjectBuilder.start().add("_id", 7).add("x", 1).add("y", "bbb").get());
126+
127+
//only sort
128+
obj = c.findOne(new BasicDBObject(), null, new BasicDBObject("x", 1) );
129+
assertNotNull(obj);
130+
assertEquals(4, obj.get("_id"));
131+
132+
obj = c.findOne(new BasicDBObject(), null, new BasicDBObject("x", -1));
133+
assertNotNull(obj);
134+
assertEquals(obj.get("_id"), 2);
135+
136+
//query and sort
137+
obj = c.findOne(new BasicDBObject("x", 1), null, BasicDBObjectBuilder.start().add("x", 1).add("y", 1).get() );
138+
assertNotNull(obj);
139+
assertEquals(obj.get("_id"), 3);
140+
141+
obj = c.findOne( QueryBuilder.start("x").lessThan(2).get(), null, BasicDBObjectBuilder.start().add("y", -1).get() );
142+
assertNotNull(obj);
143+
assertEquals(obj.get("_id"), 5);
144+
145+
}
109146

110147
/**
111148
* This was broken recently. Adding test.

0 commit comments

Comments
 (0)