Skip to content

Commit 0e25654

Browse files
Add equals operator to Atlas Search (#1606)
JAVA-5729 --------- Co-authored-by: Maxim Katcharov <[email protected]>
1 parent 3e8f905 commit 0e25654

File tree

7 files changed

+342
-3
lines changed

7 files changed

+342
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.client.model.search;
17+
18+
import com.mongodb.annotations.Beta;
19+
import com.mongodb.annotations.Reason;
20+
import com.mongodb.annotations.Sealed;
21+
22+
import java.util.UUID;
23+
24+
import java.time.Instant;
25+
26+
import org.bson.types.ObjectId;
27+
28+
/**
29+
* @see SearchOperator#equals(FieldSearchPath, boolean)
30+
* @see SearchOperator#equals(FieldSearchPath, ObjectId)
31+
* @see SearchOperator#equals(FieldSearchPath, Number)
32+
* @see SearchOperator#equals(FieldSearchPath, Instant)
33+
* @see SearchOperator#equals(FieldSearchPath, String)
34+
* @see SearchOperator#equals(FieldSearchPath, UUID)
35+
* @see SearchOperator#equalsNull(FieldSearchPath)
36+
* @since 5.3
37+
*/
38+
@Sealed
39+
@Beta(Reason.CLIENT)
40+
public interface EqualsSearchOperator extends SearchOperator {
41+
@Override
42+
EqualsSearchOperator score(SearchScore modifier);
43+
}

Diff for: driver-core/src/main/com/mongodb/client/model/search/SearchConstructibleBsonElement.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131
final class SearchConstructibleBsonElement extends AbstractConstructibleBsonElement<SearchConstructibleBsonElement> implements
3232
MustCompoundSearchOperator, MustNotCompoundSearchOperator, ShouldCompoundSearchOperator, FilterCompoundSearchOperator,
3333
ExistsSearchOperator, TextSearchOperator, AutocompleteSearchOperator,
34-
NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator, RegexSearchOperator, QueryStringSearchOperator, WildcardSearchOperator,
35-
MoreLikeThisSearchOperator,
34+
NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator,
35+
EqualsSearchOperator, MoreLikeThisSearchOperator,
36+
RegexSearchOperator, QueryStringSearchOperator, WildcardSearchOperator,
3637
ValueBoostSearchScore, PathBoostSearchScore, ConstantSearchScore, FunctionSearchScore,
3738
GaussSearchScoreExpression, PathSearchScoreExpression,
3839
FacetSearchCollector,

Diff for: driver-core/src/main/com/mongodb/client/model/search/SearchOperator.java

+97
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
import com.mongodb.annotations.Sealed;
2121
import com.mongodb.client.model.Aggregates;
2222
import com.mongodb.client.model.geojson.Point;
23+
24+
import java.util.UUID;
25+
26+
import org.bson.BsonBinary;
27+
import org.bson.BsonNull;
2328
import org.bson.BsonDocument;
2429
import org.bson.BsonType;
2530
import org.bson.Document;
@@ -29,6 +34,8 @@
2934
import java.time.Instant;
3035
import java.util.Iterator;
3136

37+
import org.bson.types.ObjectId;
38+
3239
import static com.mongodb.assertions.Assertions.isTrueArgument;
3340
import static com.mongodb.internal.Iterables.concat;
3441
import static com.mongodb.internal.client.model.Util.combineToBsonValue;
@@ -293,6 +300,96 @@ static GeoNearSearchOperator near(final Point origin, final Number pivot, final
293300
.append("pivot", notNull("pivot", pivot)));
294301
}
295302

303+
/**
304+
* Returns a {@link SearchOperator} that searches for documents where a field matches the specified value.
305+
*
306+
* @param path The indexed field to be searched.
307+
* @param value The boolean value to query for.
308+
* @return The requested {@link SearchOperator}.
309+
* @mongodb.atlas.manual atlas-search/equals/ equals operator
310+
*/
311+
static EqualsSearchOperator equals(final FieldSearchPath path, final boolean value) {
312+
return new SearchConstructibleBsonElement("equals", new Document("path", notNull("path", path).toValue())
313+
.append("value", value));
314+
}
315+
316+
/**
317+
* Returns a {@link SearchOperator} that searches for documents where a field matches the specified value.
318+
*
319+
* @param path The indexed field to be searched.
320+
* @param value The object id value to query for.
321+
* @return The requested {@link SearchOperator}.
322+
* @mongodb.atlas.manual atlas-search/equals/ equals operator
323+
*/
324+
static EqualsSearchOperator equals(final FieldSearchPath path, final ObjectId value) {
325+
return new SearchConstructibleBsonElement("equals", new Document("path", notNull("path", path).toValue())
326+
.append("value", notNull("value", value)));
327+
}
328+
329+
/**
330+
* Returns a {@link SearchOperator} that searches for documents where a field matches the specified value.
331+
*
332+
* @param path The indexed field to be searched.
333+
* @param value The number value to query for.
334+
* @return The requested {@link SearchOperator}.
335+
* @mongodb.atlas.manual atlas-search/equals/ equals operator
336+
*/
337+
static EqualsSearchOperator equals(final FieldSearchPath path, final Number value) {
338+
return new SearchConstructibleBsonElement("equals", new Document("path", notNull("path", path).toValue())
339+
.append("value", notNull("value", value)));
340+
}
341+
342+
/**
343+
* Returns a {@link SearchOperator} that searches for documents where a field matches the specified value.
344+
*
345+
* @param path The indexed field to be searched.
346+
* @param value The instant date value to query for.
347+
* @return The requested {@link SearchOperator}.
348+
* @mongodb.atlas.manual atlas-search/equals/ equals operator
349+
*/
350+
static EqualsSearchOperator equals(final FieldSearchPath path, final Instant value) {
351+
return new SearchConstructibleBsonElement("equals", new Document("path", notNull("path", path).toValue())
352+
.append("value", notNull("value", value)));
353+
}
354+
355+
/**
356+
* Returns a {@link SearchOperator} that searches for documents where a field matches the specified value.
357+
*
358+
* @param path The indexed field to be searched.
359+
* @param value The string value to query for.
360+
* @return The requested {@link SearchOperator}.
361+
* @mongodb.atlas.manual atlas-search/equals/ equals operator
362+
*/
363+
static EqualsSearchOperator equals(final FieldSearchPath path, final String value) {
364+
return new SearchConstructibleBsonElement("equals", new Document("path", notNull("path", path).toValue())
365+
.append("value", notNull("value", value)));
366+
}
367+
368+
/**
369+
* Returns a {@link SearchOperator} that searches for documents where a field matches the specified value.
370+
*
371+
* @param path The indexed field to be searched.
372+
* @param value The uuid value to query for.
373+
* @return The requested {@link SearchOperator}.
374+
* @mongodb.atlas.manual atlas-search/equals/ equals operator
375+
*/
376+
static EqualsSearchOperator equals(final FieldSearchPath path, final UUID value) {
377+
return new SearchConstructibleBsonElement("equals", new Document("path", notNull("path", path).toValue())
378+
.append("value", notNull("value", new BsonBinary(value))));
379+
}
380+
381+
/**
382+
* Returns a {@link SearchOperator} that searches for documents where a field matches null.
383+
*
384+
* @param path The indexed field to be searched.
385+
* @return The requested {@link SearchOperator}.
386+
* @mongodb.atlas.manual atlas-search/equals/ equals operator
387+
*/
388+
static EqualsSearchOperator equalsNull(final FieldSearchPath path) {
389+
return new SearchConstructibleBsonElement("equals", new Document("path", notNull("path", path).toValue())
390+
.append("value", BsonNull.VALUE));
391+
}
392+
296393
/**
297394
* Returns a {@link SearchOperator} that returns documents similar to input document.
298395
*

Diff for: driver-core/src/test/functional/com/mongodb/client/model/search/AggregatesSearchIntegrationTest.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
import static com.mongodb.client.model.search.SearchOperator.autocomplete;
8181
import static com.mongodb.client.model.search.SearchOperator.compound;
8282
import static com.mongodb.client.model.search.SearchOperator.dateRange;
83+
import static com.mongodb.client.model.search.SearchOperator.equalsNull;
8384
import static com.mongodb.client.model.search.SearchOperator.exists;
8485
import static com.mongodb.client.model.search.SearchOperator.moreLikeThis;
8586
import static com.mongodb.client.model.search.SearchOperator.near;
@@ -621,7 +622,9 @@ private static Stream<Arguments> searchAndSearchMetaArgs() {
621622
moreLikeThis(new BsonDocument("like", new BsonDocument("fieldName10",
622623
new BsonString("term6")))),
623624
wildcard(asList("term10", "term11"), asList(wildcardPath("wildc*rd"), fieldPath("title").multi(
624-
"keyword")))
625+
"keyword"))),
626+
SearchOperator.equals(fieldPath("fieldName11"), "term7"),
627+
equalsNull(fieldPath("fieldName12"))
625628
))
626629
.minimumShouldMatch(1)
627630
.mustNot(singleton(

Diff for: driver-core/src/test/unit/com/mongodb/client/model/search/SearchOperatorTest.java

+108
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,22 @@
1818
import com.mongodb.MongoClientSettings;
1919
import com.mongodb.client.model.geojson.Point;
2020
import com.mongodb.client.model.geojson.Position;
21+
22+
import java.util.UUID;
23+
2124
import org.bson.BsonArray;
25+
import org.bson.BsonBinary;
26+
import org.bson.BsonBoolean;
2227
import org.bson.BsonDateTime;
2328
import org.bson.BsonDocument;
2429
import org.bson.BsonDouble;
2530
import org.bson.BsonInt32;
2631
import org.bson.BsonInt64;
32+
import org.bson.BsonNull;
33+
import org.bson.BsonObjectId;
2734
import org.bson.BsonString;
2835
import org.bson.Document;
36+
import org.bson.types.ObjectId;
2937
import org.junit.jupiter.api.Test;
3038

3139
import java.time.Duration;
@@ -581,6 +589,106 @@ void near() {
581589
);
582590
}
583591

592+
@Test
593+
void equals() {
594+
ObjectId objectId = new ObjectId();
595+
UUID uuid = UUID.randomUUID();
596+
assertAll(
597+
() -> assertThrows(IllegalArgumentException.class, () ->
598+
// path must not be null
599+
SearchOperator.equals(null, "term")
600+
),
601+
() -> assertEquals(
602+
new BsonDocument("equals",
603+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
604+
.append("value", new BsonBoolean(true))
605+
),
606+
SearchOperator.equals(
607+
fieldPath("fieldName"),
608+
true)
609+
.toBsonDocument()
610+
),
611+
() -> assertEquals(
612+
new BsonDocument("equals",
613+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
614+
.append("value", new BsonObjectId(objectId))
615+
),
616+
SearchOperator.equals(
617+
fieldPath("fieldName"),
618+
objectId)
619+
.toBsonDocument()
620+
),
621+
() -> assertEquals(
622+
new BsonDocument("equals",
623+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
624+
.append("value", new BsonInt32(1))
625+
),
626+
SearchOperator.equals(
627+
fieldPath("fieldName"),
628+
1)
629+
.toBsonDocument()
630+
),
631+
() -> assertEquals(
632+
new BsonDocument("equals",
633+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
634+
.append("value", new BsonInt64(Long.MAX_VALUE))
635+
),
636+
SearchOperator.equals(
637+
fieldPath("fieldName"),
638+
Long.MAX_VALUE)
639+
.toBsonDocument()
640+
),
641+
() -> assertEquals(
642+
new BsonDocument("equals",
643+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
644+
.append("value", new BsonDouble(Double.MAX_VALUE))
645+
),
646+
SearchOperator.equals(
647+
fieldPath("fieldName"),
648+
Double.MAX_VALUE)
649+
.toBsonDocument()
650+
),
651+
() -> assertEquals(
652+
new BsonDocument("equals",
653+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
654+
.append("value", new BsonDateTime(Instant.EPOCH.toEpochMilli()))
655+
),
656+
SearchOperator.equals(
657+
fieldPath("fieldName"),
658+
Instant.EPOCH)
659+
.toBsonDocument()
660+
),
661+
() -> assertEquals(
662+
new BsonDocument("equals",
663+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
664+
.append("value", new BsonString("term"))
665+
),
666+
SearchOperator.equals(
667+
fieldPath("fieldName"),
668+
"term")
669+
.toBsonDocument()
670+
),
671+
() -> assertEquals(
672+
new BsonDocument("equals",
673+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
674+
.append("value", new BsonBinary(uuid))
675+
),
676+
SearchOperator.equals(
677+
fieldPath("fieldName"),
678+
uuid)
679+
.toBsonDocument()
680+
),
681+
() -> assertEquals(
682+
new BsonDocument("equals",
683+
new BsonDocument("path", fieldPath("fieldName").toBsonValue())
684+
.append("value", BsonNull.VALUE)
685+
),
686+
SearchOperator.equalsNull(fieldPath("fieldName"))
687+
.toBsonDocument()
688+
)
689+
);
690+
}
691+
584692
@Test
585693
void moreLikeThis() {
586694
assertAll(

0 commit comments

Comments
 (0)