I'm trying to implement the text search in MongoDB, in C#.
The documentation doesn't cover anything about how to sort the text search results in C#.
I have a list of tags, separated by spaces, to match.
If I provide a string like "Tag1 Tag2", I would like the results to be provided in the following order:
I have been trying to piece together some code:
var F = Builders<MongoPost>.Filter.Text(Tags);
var S = Builders<MongoPost>.Sort.MetaTextScore("textScore");
return Mongo.Driver.Find(F).Sort(S).ToListAsync().Result;
But I get the following error:
{"QueryFailure flag was true (response was { \"$err\" : \"Can't canonicalize query: BadValue must have $meta projection for all $meta sort keys\", \"code\" : 17287 })."}
No proper documentation for this error...
Then I found the following code on this site:
var pipeline = new List<BsonDocument>
{
BsonSerializer.Deserialize<BsonDocument>("{ $match: { $text: { $search: \"" + Tags + "\" } } }"),
BsonSerializer.Deserialize<BsonDocument>("{ $sort: { score: { $meta: \"textScore\" } } }")
};
var R = Mongo.Driver.AggregateAsync(new BsonDocumentStagePipelineDefinition<MongoPost, MongoPost>(pipeline)).Result;
return R.ToListAsync().Result;
At least is runs without error, but I am trying to make the code in the style at the top, like you can do for the rest of the API, and not having to go back to console style text strings that have to be parsed for every execution. Also, I need to add a lot more criteria to the search, so this syntax is not practical for me.
Is there any proper documentation I missed? If not, does anyone know how to implement this in the style at the top?
Using this post: Retrieve Relevance Ordered Result from Text Query on MongoDB Collection using the C# Driver
I got it to work with the following code:
var F = Builders<MongoPost>.Filter.Text(Tags);
var P = Builders<MongoPost>.Projection.MetaTextScore("TextMatchScore");
var S = Builders<MongoPost>.Sort.MetaTextScore("TextMatchScore");
return Mongo.Driver.Find(F).Project<MongoPost>(P).Sort(S).ToListAsync().Result;
And my class MongoPost has the following field:
[BsonIgnoreIfNull]
public double? TextMatchScore { get; set; }
Alternatively you could add convention pack to ignore extra elements for all models or only for this particular one and then you won't need to add extra property:
ConventionRegistry.Register("conventions", new ConventionPack
{
new IgnoreExtraElementsConvention(true)
}, type => true));
And then the pipeline will look as follows:
var sortedResult = await collection
.Find(Builders<Model>.Filter.Text(searchTerm))
.Project<Model>(Builders<Model>.Projection.MetaTextScore("score"))
.Sort(Builders<Model>.Sort.MetaTextScore("score"))
.ToListAsync();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With