在 mongo 数据库驱动程序 c# 中使用 $in 子句进行不敏感搜索

Using $in clause for insensitive search in mongo db driver c#

我想知道如何对 $in 表达式使用不区分大小写的方式。

根据官方 MongoDB 手册,您可以这样做:

{ name: { $in: [ /^acme/i, /^ack/ ] } }

我在 Compass 上测试了这个,它工作正常,搜索不敏感。

我需要使用 C# 中的 Mongo 驱动程序。

我正在这样做:

  var array = new BsonArray(companyNames);

  var filter = new BsonDocument { { "Name", new BsonDocument { { "$in", new BsonArray(array) }} } };
  var result = _collection.Find(filter).ToList();

companyNames 是一个字符串[]

但是,这只会检索到完全匹配项。这很明显,因为我没有包括 "regex" 表达式。但我不知道如何将正则表达式包含在字符串中。

解决方法是为每个公司名称创建一个带有正则表达式的 $or 表达式。

有人知道怎么做吗?

谢谢

mongo-csharp-driver, you can utilise MongoDB.Bson.BsonRegularExpression。您可以执行:

var arrayIn = new BsonArray().Add(
                      new BsonRegularExpression("^acme", "i")
                  ).Add(
                      new BsonRegularExpression("^ack"));
var filter = new BsonDocument { { "name", new BsonDocument { { "$in", arrayIn }} } };
var cursor = collection.Find(filter).ToList();

或者,代替 string 使用 Regex and RegexOptions

var arrayIn = new BsonArray().Add(
                      new BsonRegularExpression(
                          new Regex(
                              "^acme", RegexOptions.IgnoreCase))
                  ).Add(new BsonRegularExpression(
                              "^ack"));

这是一个在公司名称字段上使用文本索引的优雅解决方案。

using MongoDB.Entities;

namespace Whosebug
{
    class Program
    {
        public class Company : Entity
        {
            public string Name { get; set; }
        }

        static void Main(string[] args)
        {
            new DB("test");

            DB.Index<Company>()
              .Key(c => c.Name, KeyType.Text)
              .Option(o => o.Background = false)
              .Create();

            var c1 = new Company { Name = "Ackme" };
            var c2 = new Company { Name = "Acme" };
            var c3 = new Company { Name = "Lackme" };
            var c4 = new Company { Name = "Hackme" };

            c1.Save(); c2.Save(); c3.Save(); c4.Save();

            var names = new[] { "ackme", "acme" };

            var result = DB.SearchText<Company>(string.Join(" ", names));
        }
    }
}

请注意,上面使用了便利库 MongoDB.Entities。但是概念是一样的,但是官方驱动的语法比上面的要麻烦

我的解决方案是重载 .In() 作为扩展方法,采用额外的参数来区分大小写:

public static class MongoExtensions
{
    public static FilterDefinition<TDocument> In<TDocument>(
        this FilterDefinitionBuilder<TDocument> builder,
        Expression<Func<TDocument, object>> expr,
        IEnumerable<string> values,
        bool ignoreCase)
    {
        if (!ignoreCase)
        {
            return builder.In(expr, values);
        }

        var filters = values
            .Select(v => builder.Regex(expr, new BsonRegularExpression($"^{Regex.Escape(v)}$", "i")));

        return builder.Or(filters);
    }
}

那么你可以简单地:

var filter = Builders<Companies>.Filter.In(c => c.Name, companyNames, true);
var result = _collection.Find(filter).ToList();