Skip to content

Commit 22006bd

Browse files
authored
Add wildcard operator to Atlas Search (#1596)
Add wildcard operator to Atlas Search There are several Atlas Search query operators that are not implemented with first class support in the Java driver. This PR adds the wildcard operator to Atlas Search. JAVA-5745
1 parent 0d87508 commit 22006bd

File tree

7 files changed

+137
-2
lines changed

7 files changed

+137
-2
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
final class SearchConstructibleBsonElement extends AbstractConstructibleBsonElement<SearchConstructibleBsonElement> implements
3232
MustCompoundSearchOperator, MustNotCompoundSearchOperator, ShouldCompoundSearchOperator, FilterCompoundSearchOperator,
3333
ExistsSearchOperator, TextSearchOperator, AutocompleteSearchOperator,
34-
NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator, RegexSearchOperator, QueryStringSearchOperator,
34+
NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator, RegexSearchOperator, QueryStringSearchOperator, WildcardSearchOperator,
3535
ValueBoostSearchScore, PathBoostSearchScore, ConstantSearchScore, FunctionSearchScore,
3636
GaussSearchScoreExpression, PathSearchScoreExpression,
3737
FacetSearchCollector,

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

+30
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,36 @@ static PhraseSearchOperator phrase(final Iterable<? extends SearchPath> paths, f
339339
.append("query", queryIterator.hasNext() ? queries : firstQuery));
340340
}
341341

342+
/**
343+
* Returns a {@link SearchOperator} that performs a search using a special characters in the search string that can match any character.
344+
*
345+
* @param query The string to search for.
346+
* @param path The indexed field to be searched.
347+
* @return The requested {@link SearchOperator}.
348+
* @mongodb.atlas.manual atlas-search/wildcard/ wildcard operator
349+
*/
350+
static WildcardSearchOperator wildcard(final String query, final SearchPath path) {
351+
return wildcard(singleton(notNull("query", query)), singleton(notNull("path", path)));
352+
}
353+
354+
/**
355+
* Returns a {@link SearchOperator} that performs a search using a special characters in the search string that can match any character.
356+
*
357+
* @param queries The non-empty strings to search for.
358+
* @param paths The non-empty index fields to be searched.
359+
* @return The requested {@link SearchOperator}.
360+
* @mongodb.atlas.manual atlas-search/wildcard/ wildcard operator
361+
*/
362+
static WildcardSearchOperator wildcard(final Iterable<String> queries, final Iterable<? extends SearchPath> paths) {
363+
Iterator<String> queryIterator = notNull("queries", queries).iterator();
364+
isTrueArgument("queries must not be empty", queryIterator.hasNext());
365+
String firstQuery = queryIterator.next();
366+
Iterator<? extends SearchPath> pathIterator = notNull("paths", paths).iterator();
367+
isTrueArgument("paths must not be empty", pathIterator.hasNext());
368+
return new SearchConstructibleBsonElement("wildcard", new Document("query", queryIterator.hasNext() ? queries : firstQuery)
369+
.append("path", combineToBsonValue(pathIterator, false)));
370+
}
371+
342372
/**
343373
* Returns a {@link SearchOperator} that performs a search using a regular expression.
344374
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
/**
23+
* @see SearchOperator#wildcard(String, SearchPath)
24+
* @see SearchOperator#wildcard(Iterable, Iterable)
25+
* @since 4.7
26+
*/
27+
@Sealed
28+
@Beta(Reason.CLIENT)
29+
public interface WildcardSearchOperator extends SearchOperator {
30+
@Override
31+
WildcardSearchOperator score(SearchScore modifier);
32+
}

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import static com.mongodb.client.model.search.SearchOperator.regex;
8787
import static com.mongodb.client.model.search.SearchOperator.phrase;
8888
import static com.mongodb.client.model.search.SearchOperator.text;
89+
import static com.mongodb.client.model.search.SearchOperator.wildcard;
8990
import static com.mongodb.client.model.search.SearchOptions.searchOptions;
9091
import static com.mongodb.client.model.search.SearchPath.fieldPath;
9192
import static com.mongodb.client.model.search.SearchPath.wildcardPath;
@@ -614,7 +615,8 @@ private static Stream<Arguments> searchAndSearchMetaArgs() {
614615
near(Instant.ofEpochMilli(1), Duration.ofMillis(3), fieldPath("fieldName9")),
615616
phrase(fieldPath("fieldName10"), "term6"),
616617
regex(fieldPath("fieldName11"), "term7"),
617-
queryString(fieldPath("fieldName12"), "term8")
618+
queryString(fieldPath("fieldName12"), "term8"),
619+
wildcard(asList("term10", "term11"), asList(wildcardPath("wildc*rd"), fieldPath("fieldName14")))
618620
))
619621
.minimumShouldMatch(1)
620622
.mustNot(singleton(

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

+42
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,48 @@ void near() {
581581
);
582582
}
583583

584+
@Test
585+
void wildcard() {
586+
assertAll(
587+
() -> assertThrows(IllegalArgumentException.class, () ->
588+
// queries must not be empty
589+
SearchOperator.wildcard(emptyList(), singleton(fieldPath("fieldName")))
590+
),
591+
() -> assertThrows(IllegalArgumentException.class, () ->
592+
// paths must not be empty
593+
SearchOperator.wildcard(singleton("term"), emptyList())
594+
),
595+
() -> assertEquals(
596+
new BsonDocument("wildcard",
597+
new BsonDocument("query", new BsonString("term"))
598+
.append("path", fieldPath("fieldName").toBsonValue())
599+
),
600+
SearchOperator.wildcard(
601+
"term",
602+
fieldPath("fieldName"))
603+
.toBsonDocument()
604+
),
605+
() -> assertEquals(
606+
new BsonDocument("wildcard",
607+
new BsonDocument("query", new BsonArray(asList(
608+
new BsonString("term1"),
609+
new BsonString("term2"))))
610+
.append("path", new BsonArray(asList(
611+
fieldPath("fieldName").toBsonValue(),
612+
wildcardPath("wildc*rd").toBsonValue())))
613+
),
614+
SearchOperator.wildcard(
615+
asList(
616+
"term1",
617+
"term2"),
618+
asList(
619+
fieldPath("fieldName"),
620+
wildcardPath("wildc*rd")))
621+
.toBsonDocument()
622+
)
623+
);
624+
}
625+
584626
@Test
585627
void queryString() {
586628
assertAll(

Diff for: driver-scala/src/main/scala/org/mongodb/scala/model/search/SearchOperator.scala

+21
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,27 @@ object SearchOperator {
228228
def near(origin: Point, pivot: Number, paths: Iterable[_ <: FieldSearchPath]): GeoNearSearchOperator =
229229
JSearchOperator.near(origin, pivot, paths.asJava)
230230

231+
/**
232+
* Returns a `SearchOperator` that enables queries which use special characters in the search string that can match any character.
233+
*
234+
* @param query The string to search for.
235+
* @param path The indexed field to be searched.
236+
* @return The requested `SearchOperator`.
237+
* @see [[https://www.mongodb.com/docs/atlas/atlas-search/wildcard/ wildcard operator]]
238+
*/
239+
def wildcard(query: String, path: SearchPath): WildcardSearchOperator = JSearchOperator.wildcard(query, path)
240+
241+
/**
242+
* Returns a `SearchOperator` that enables queries which use special characters in the search string that can match any character.
243+
*
244+
* @param queries The non-empty strings to search for.
245+
* @param paths The non-empty indexed fields to be searched.
246+
* @return The requested `SearchOperator`.
247+
* @see [[https://www.mongodb.com/docs/atlas/atlas-search/wildcard/ wildcard operator]]
248+
*/
249+
def wildcard(queries: Iterable[String], paths: Iterable[_ <: SearchPath]): WildcardSearchOperator =
250+
JSearchOperator.wildcard(queries.asJava, paths.asJava)
251+
231252
/**
232253
* Returns a `SearchOperator` that supports querying a combination of indexed fields and values.
233254
*

Diff for: driver-scala/src/main/scala/org/mongodb/scala/model/search/package.scala

+8
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ package object search {
198198
@Beta(Array(Reason.CLIENT))
199199
type GeoNearSearchOperator = com.mongodb.client.model.search.GeoNearSearchOperator
200200

201+
/**
202+
* @see `SearchOperator.wildcard(String, SearchPath)`
203+
* @see `SearchOperator.wildcard(Iterable, Iterable)`
204+
*/
205+
@Sealed
206+
@Beta(Array(Reason.CLIENT))
207+
type WildcardSearchOperator = com.mongodb.client.model.search.WildcardSearchOperator
208+
201209
/**
202210
* @see `SearchOperator.queryString`
203211
*/

0 commit comments

Comments
 (0)