MongoDB文本搜索与投影
本文关键字:投影 搜索 文本 MongoDB | 更新日期: 2023-09-27 18:10:31
使用MongoDB与c#和驱动程序2.0,我试图做以下事情:
- 文本搜索
- 按文本搜索分数排序
- 项目BigClass到SmallClass
下面是这些类的(简化版本):
class BigClass
{
[BsonIgnoreIfDefault]
public ObjectId _id { get; set; }
public string Guid { get; set; }
public string Title { get; set; }
public DateTime CreationTime { get; set; }
// lots of other stuff
[BsonIgnoreIfNull]
public double? TextMatchScore { get; set; } // Temporary place for the text match score, for sorting
}
class SmallClass
{
[BsonIgnoreIfDefault]
public ObjectId _id { get; set; }
public string Title { get; set; }
[BsonIgnoreIfNull]
public double? TextMatchScore { get; set; } // Temporary place for the text match score, for sorting
}
如果我做一个文本搜索,它是非常简单的:
var F = Builders<BigClass>.Filter.Text("text I am looking for");
var Result = MongoDriver.Find(F).ToListAsync().Result;
如果我想按文本搜索的分数排序,那就有点混乱了(而且文档记录很差):
var F = Builders<BigClass>.Filter.Text("text I am looking for");
var P = Builders<BigClass>.Projection.MetaTextScore("TextMatchScore");
var S = Builders<BigClass>.Sort.MetaTextScore("TextMatchScore");
var Result = MongoDriver.Find(F).Project<BigClass>.Sort(S).ToListAsync().Result;
本质上它需要我在类(TextMatchScore)中添加一个字段来保存结果。
如果我想获得数据,而不需要排序并将其投影到SmallClass,这很简单:
var F = Builders<BigClass>.Filter.Text("text I am looking for");
var P = Builders<BigClass>.Projection.Include(_ => _.id).Include(_ => _.Title);
var Result = MongoDriver.Find(F).Project<SmallClass>(P).ToListAsync().Result;
现在,如果"I want it all",问题就出现了:
var F = Builders<BigClass>.Filter.Text("text I am looking for");
var P = Builders<BigClass>.Projection.MetaTextScore("TextMatchScore").Include(_ => _.id).Include(_ => _.Title).Include(_ => _.TextMatchScore);
var S = Builders<BigClass>.Sort.MetaTextScore("TextMatchScore");
var Result = MongoDriver.Find(F).Project<SmallClass>.Sort(S).ToListAsync().Result;
我得到一个异常:
Message = "QueryFailure flag was true (response was { '"$err'" : '"Can't canonicalize query: BadValue must have $meta projection for all $meta sort keys'", '"code'" : 17287 })."
正如预期的那样,这个错误没有记录在任何地方,因为Mongo的家伙希望用户自己记录一切。
如果我做投影到'BigClass',没有问题,代码运行,只是填充正确的字段。
如果你用c#搜索文本,你找到的帖子是我的,当我试图弄清楚文本搜索,这也是很差的文档。
所以当我们把投影、文本搜索和排序结合起来时,似乎没有任何例子,我就是不能让它工作。
有谁知道这个问题的原因吗?这个适合我:
var client = new MongoClient();
var db = client.GetDatabase("test");
var col = db.GetCollection<BigClass>("big");
await db.DropCollectionAsync(col.CollectionNamespace.CollectionName);
await col.Indexes.CreateOneAsync(Builders<BigClass>.IndexKeys.Text(x => x.Title));
await col.InsertManyAsync(new[]
{
new BigClass { Title = "One Jumped Over The Moon" },
new BigClass { Title = "Two went Jumping Over The Sun" }
});
var filter = Builders<BigClass>.Filter.Text("Jump Over");
// don't need to Include(x => x.TextMatchScore) because it's already been included with MetaTextScore.
var projection = Builders<BigClass>.Projection.MetaTextScore("TextMatchScore").Include(x => x._id).Include(x => x.Title);
var sort = Builders<BigClass>.Sort.MetaTextScore("TextMatchScore");
var result = await col.Find(filter).Project<SmallClass>(projection).Sort(sort).ToListAsync();
我删除了TextMatchScore的包含。它仍然会回来,因为它被包含在MetaTextScore("TextMatchScore")中。
文档是一个正在进行的工作。我们首先处理主要的用例,因为这些用例影响最多的人。这个用例并不常见,也没有被记录。我们当然接受拉取请求,包括代码和文档。另外,您也可以在jira.mongodb.org上提交CSHARP项目下的文档申请。
解决方案在MongoDB中工作。司机2。X如下。重要的是不要做Include in Projection,因为它会擦除默认的,(或者记得添加适当的投影)
查询: {
"find":"SoceCollection",
"filter":{
"$text":{
"$search":"some text to search"
}
},
"sort":{
"TextScore":{
"$meta":"textScore"
}
},
"projection":{
"TextScore":{
"$meta":"textScore"
},
"_id":0,
"CreatedDate":0
},
"limit":20,
"collation":{
"locale":"en",
"strength":1
} ...
代码var sort = Builders<BigModel>.Sort.MetaTextScore(nameof(LightModel.TextScore));
var projection = Builders<BigModel>.Projection
.MetaTextScore(nameof(LightModel.TextScore))
.Exclude(x => x.Id)
.Exclude(x => x.CreatedDate);
return await Collection()
.Find(filter, new FindOptions { Collation = new Collation("en", strength: CollationStrength.Primary) })
.Project<LightModel>(projection)
.Sort(sort)
.Limit(20)
.ToListAsync();