Skip to content

Commit 34ddb22

Browse files
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 cb5483c commit 34ddb22

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-3898
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)