Skip to content

Commit 132834b

Browse files
christophstrobljxblum
authored andcommitted
Retain sort order when using text search sort by score.
We now make sure to capture the position to apply sort by score.
1 parent 36a4b7f commit 132834b

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/TextQuery.java

+27-5
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
package org.springframework.data.mongodb.core.query;
1717

1818
import java.util.Locale;
19+
import java.util.Map.Entry;
1920

2021
import org.bson.Document;
21-
2222
import org.springframework.data.mongodb.util.BsonUtils;
2323
import org.springframework.lang.Nullable;
2424

@@ -37,6 +37,7 @@ public class TextQuery extends Query {
3737
private String scoreFieldName = DEFAULT_SCORE_FIELD_FIELDNAME;
3838
private boolean includeScore = false;
3939
private boolean sortByScore = false;
40+
private int sortByScoreIndex = 0;
4041

4142
/**
4243
* Creates new {@link TextQuery} using the the given {@code wordsAndPhrases} with {@link TextCriteria}
@@ -101,6 +102,7 @@ public static TextQuery queryText(TextCriteria criteria) {
101102
*/
102103
public TextQuery sortByScore() {
103104

105+
this.sortByScoreIndex = getSortObject().size();
104106
this.includeScore();
105107
this.sortByScore = true;
106108
return this;
@@ -173,15 +175,35 @@ public Document getFieldsObject() {
173175
public Document getSortObject() {
174176

175177
if (this.sortByScore) {
176-
Document sort = new Document();
177-
sort.put(getScoreFieldName(), META_TEXT_SCORE);
178-
sort.putAll(super.getSortObject());
179-
return sort;
178+
if (sortByScoreIndex == 0) {
179+
Document sort = new Document();
180+
sort.put(getScoreFieldName(), META_TEXT_SCORE);
181+
sort.putAll(super.getSortObject());
182+
return sort;
183+
}
184+
return fitInSortByScoreAtPosition(super.getSortObject());
180185
}
181186

182187
return super.getSortObject();
183188
}
184189

190+
private Document fitInSortByScoreAtPosition(Document source) {
191+
192+
Document target = new Document();
193+
int i = 0;
194+
for (Entry<String, Object> entry : source.entrySet()) {
195+
if (i == sortByScoreIndex) {
196+
target.put(getScoreFieldName(), META_TEXT_SCORE);
197+
}
198+
target.put(entry.getKey(), entry.getValue());
199+
i++;
200+
}
201+
if (i == sortByScoreIndex) {
202+
target.put(getScoreFieldName(), META_TEXT_SCORE);
203+
}
204+
return target;
205+
}
206+
185207
/*
186208
* (non-Javadoc)
187209
* @see org.springframework.data.mongodb.core.query.Query#isSorted()

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/TextQueryUnitTests.java

+26-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717

1818
import static org.springframework.data.mongodb.test.util.Assertions.*;
1919

20-
import org.junit.jupiter.api.Test;
20+
import java.util.Map.Entry;
2121

22+
import org.junit.jupiter.api.Test;
2223
import org.springframework.data.domain.Sort;
2324
import org.springframework.data.domain.Sort.Direction;
2425

@@ -94,4 +95,28 @@ public void shouldUseCustomFieldnameForScoring() {
9495
assertThat(query.getSortObject()).containsKey("customFieldForScore");
9596
}
9697

98+
@Test // GH-3896
99+
public void retainsSortOrderWhenUsingScore() {
100+
101+
TextQuery query = new TextQuery(QUERY);
102+
query.with(Sort.by(Direction.DESC, "one"));
103+
query.sortByScore();
104+
query.with(Sort.by(Direction.DESC, "two"));
105+
106+
assertThat(query.getSortObject().entrySet().stream().map(Entry::getKey)).containsExactly("one", "score", "two");
107+
108+
query = new TextQuery(QUERY);
109+
query.with(Sort.by(Direction.DESC, "one"));
110+
query.sortByScore();
111+
112+
assertThat(query.getSortObject().entrySet().stream().map(Entry::getKey)).containsExactly("one", "score");
113+
114+
query = new TextQuery(QUERY);
115+
query.sortByScore();
116+
query.with(Sort.by(Direction.DESC, "one"));
117+
query.with(Sort.by(Direction.DESC, "two"));
118+
119+
assertThat(query.getSortObject().entrySet().stream().map(Entry::getKey)).containsExactly("score", "one", "two");
120+
}
121+
97122
}

0 commit comments

Comments
 (0)