I am attempting to text query a collection and retrieve the results in the text match order. The docs explain pretty well how to do this in the shell:
db.articles.find(
{ status: "A", $text: { $search: "coffee cake" } },
{ score: { $meta: "textScore" } }
).sort( { date: 1, score: { $meta: "textScore" } } )
but it requires the projection of the additional score
field from the find into the sort.
In C#, I have a function that looks like this:
public IEnumerable<T> TextSearch<T>(MongoCollection<T> coll, string text) {
var cursor = coll.Find(Query.Text(text))
.SetSortOrder(SortBy<T>.MetaTextScore(???));
foreach(var t in cursor) {
// strip projected score from value
yield return t;
}
}
but I am missing how to project the "textScore" value into my results, so that I can specify the column to MetaTextScore
in SetSortOrder
.
I was able to get this working through trial and error. The trick is that your data object needs to have a field on it already that will hold the MetaTextScore
value. So given the interface:
interface ITextSearchSortable {
double? TextMatchScore { get; set; }
}
the final function looks like this:
public IEnumerable<T> TextSearch<T>(MongoCollection<T> coll, string text) where T:ITextSearchSortable {
var cursor = coll.Find(Query.Text(text))
.SetFields(Fields<T>.MetaTextScore(t => t.TextMatchScore))
.SetSortOrder(SortBy<T>MetaTextScore(t => t.TextMatchScore));
foreach(var t in cursor) {
// prevent saving the value back into the database
t.TextMatchScore = null;
yield return t;
}
}
It's worth noting that TextMatchScore
can't have a [BsonIgnore]
decoration, or there will be an exception. However, it can have a [BsonIgnoreIfNull]
decoration. So by scrubbing the value off the data object before yielding it, the data object can be saved back into the collection without putting in a garbage value.