You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C# MongoDB Driver查询content任意位置含指定值的文档?

问题描述

我用C#编写了ASP.NET Core 9.0 Web API,使用MongoDB Driver 3.1版本查询MongoDB。数据库里有个Foo集合,存储多源数据,Schema如下:

_id: objectId,
sourceName: string,
content: document

content字段的结构完全不固定,比如:

{
  "_id": ObjectId('66c63a62a9fa7c172aea24f8'),
  "sourceName": "Foo-1",
  "content": {
    "opName": "Django",
    "opId": 3,
    "accounts": ["sample1", "joe@google.com"]
  }
},
{
  "_id": ObjectId('66c63a62a9fa7c172aea24f9'),
  "sourceName": "Foo-2",
  "content": {
    "magazine": "Foo for beginners",
    "author": "Joe Blogs"
  }
}

需求是查找所有content中任意位置包含指定术语(比如"Joe")的文档,不管匹配的是哪个键,只要值里有这个术语就行。我尝试过用正则表达式查询,但没得到结果:

// request.Term = "Joe"
// _foo = mongoDbService.Database?.GetCollection<Foo>("foo");

var regex = new Regex(Regex.Escape(request.Term), RegexOptions.IgnoreCase);
var filter = Builders<Foo>.Filter.Regex(r => r.Content, new BsonRegularExpression(regex));

await _foo.Find(filter).ToListAsync()

Foo的C#类定义:

[BsonIgnoreExtraElements]
public class Foo
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    [BsonElement("sourceName")]
    public string Source { get; set; }

    [BsonElement("content")]
    public BsonDocument Content { get; set; }
}

请问怎么查询content字段,判断其任意键的值是否包含、以指定词开头或结尾?

解决方案

为什么之前的方法无效

直接对Content字段用Regex过滤,MongoDB会尝试匹配整个content文档的BSON序列化字符串,而不是遍历里面的每个值,所以无法命中嵌套的字段或数组元素。

方法1:使用$expr+$objectToArray遍历所有值

利用MongoDB的聚合表达式,把content转换成键值对数组,然后遍历所有值进行正则匹配:

var term = request.Term;
var regex = new BsonRegularExpression(Regex.Escape(term), "i"); // "i"表示忽略大小写

var filter = Builders<Foo>.Filter.Expr(
    BsonDocument.Parse($"{{ $anyElementTrue: {{ $map: {{ input: {{ $objectToArray: '$content' }}, as: 'kv', in: {{ $regexMatch: {{ input: '$$kv.v', regex: {regex.ToBsonDocument()} }} }} }} }} }}")
);

var result = await _foo.Find(filter).ToListAsync();

解释:

  • $objectToArray: '$content':把content文档转成[{k: "key1", v: "value1"}, ...]的数组
  • $map:遍历每个键值对,用$regexMatch检查值是否匹配正则
  • $anyElementTrue:只要有一个匹配结果为true,就返回该文档

方法2:创建文本索引(推荐,性能更优)

如果频繁做这类模糊搜索,建议给content字段创建通配符文本索引:

// 在MongoDB Shell中执行
db.foo.createIndex({"content.$**": "text"})

之后在C#中可以用文本搜索过滤:

var filter = Builders<Foo>.Filter.Text(request.Term, new TextSearchOptions { CaseSensitive = false });
var result = await _foo.Find(filter).ToListAsync();

注意:

  • 文本索引会自动处理数组元素(比如accounts数组里的字符串)
  • 支持模糊匹配,但默认是按词匹配,如果需要前缀匹配可以调整索引参数
  • 性能比聚合表达式好,适合大规模数据

针对开头/结尾匹配的调整

如果需要精确的"以指定词开头"或"结尾",修改正则表达式即可:

  • 开头匹配:new BsonRegularExpression($"^{Regex.Escape(term)}", "i")
  • 结尾匹配:new BsonRegularExpression($"{Regex.Escape(term)}$", "i")

内容的提问来源于stack exchange,提问作者Leigh.D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 13:43:11