.net 如何使用http请求中的查询字符串过滤mongodb.find()集合?

g2ieeal7  于 2022-11-19  发布在  .NET
关注(0)|答案(1)|浏览(135)

我正在尝试创建一个简单的REST API,它能够使用一些简单的URL查询参数来过滤资源,例如:***"/Profile?firstName=Brian&age=26”***。我不需要任何高级过滤,只需找到所有匹配的内容即可。
我在.Net 6和MongoDB中使用最小API。驱动程序(2.17.1)
我有一个“解决方案”,工作,但它的错误倾向,是不是很可扩展或灵活。
如何能够读取查询参数,而不硬编码每个端点的特定名称和类型,同时不丢失参数的类型。如果可能,请使用过滤器生成器,而不是json。

当前“解决方案”:

配置文件类的一部分

public class Profile : Entity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    ...
    public List<BasePreference> Preferences { get; set; }

    public Profile()
    {
        Preferences = new List<BasePreference>();
    }
}

应用程序.MapGet(“/配置文件”,测试2);

private static async Task<IResult> Test2(
    IRepository<Profile> repo,
    string? firstName,
    string? lastName,
    int? age)
{
    Dictionary<string, object?> queryDict= new Dictionary<string, object?>();
    queryDict.Add(nameof(firstName),firstName);
    queryDict.Add(nameof(lastName),lastName);
    queryDict.Add(nameof(age), age);

    foreach (var pair in queryDict)
    {
        if(pair.Value is null)
        {
            data.Remove(pair.Key);
        }
    }

    var query = JsonSerializer.Serialize(data);

    var content = await repo.ReadMany(query);

    return Results.Ok(content);
}

MongoDB储存库片段

private IMongoCollection<T> collection;

public MongoDBRepository(IOptions<MongoDBSettings> mongoDBSettings)
{
    MongoClient client = new MongoClient(mongoDBSettings.Value.ConnectionURI);

    IMongoDatabase database = client.GetDatabase(mongoDBSettings.Value.DatabaseName);

    collection = database.GetCollection<T>(typeof(T).Name.ToLower());
}

public async Task<List<T>> ReadMany(string query)
{
    FilterDefinition<T> filter = query;

    List<T> list = await collection.Find(filter).ToListAsync();

    return list;
}

我对这种方法的问题是多方面的:

  • 为多个资源重复实施此解决方案会让人头脑发昏,而且容易出错
  • MongoDB内的大写字母必须完全匹配
  • 对Model类的更改需要在项目的不同部分进行多次更改
  • 它不能处理任何“复杂”的数据类型。例如,日期时间,GUID。

我尝试过的事情
我尝试过将所有内容转换为Json字符串并忽略类型,但是根据MongoDB,age:“25”=/= age:25。

  • 然后,我搜索了在mongoDB中允许“25”== 25的方法,但没有任何运气。我尝试创建一个只包含可查询属性的ProfileQueryModel,然后使用[FromParameters],但无法使绑定工作,也不确定如何将其转换为FilterDefinition。
  • 我试过将搜索查询Map到Dictionary〈string,object〉,但没有成功。我读到.Net 7可能包含了一种实现这一点的方法,但还没有发布。
  • 我曾尝试将查询参数设置为单个json对象,例如“/profiles?query={“firstName”:“Brian”,“age”:25”},但再次将其作为字符串设置在int上

我在寻找什么
我不需要能够过滤数组或子对象中的元素。只要在所有给定的字段上进行简单的相等。理想情况下,我希望有一个解决方案,我不使用Json作为FilterDefinition,因为这看起来不太可能与更高级的数据类型中断,也不需要任何Json转换。但我已经为一个多星期了,我对我能得到的任何改进都很满意。
感谢提前和感谢阅读到目前为止。

pinkon5k

pinkon5k1#

您可以只迭代参数并为mongo构建过滤器字符串吗?
例如:

foreach(string key in Request.QueryString) 
{
    var value = Request.QueryString[key];
}

另请参阅:similar

**已添加:**我是这样做的,在this post的帮助下,通过循环Request.Query并使用FilterDefinitionBuilder
路线:

[HttpGet]
        [Route("dynamicFilter")]
        public async Task<IActionResult> GetFilter()
        {
            if (Request.Query != null)
            {
                var stream = await _Repository.GetFilter(Request.Query);
                if (stream == null)
                {
                    return NotFound();
                }
                return Ok(stream);
            }

            return BadRequest("Parameter not found or is invalid");    
        }

        public async Task<List<Message>> GetFilter(IQueryCollection iRequest)
        {
            FilterDefinition<Message> filterDef = BuildFilterDef(iRequest);
            //List<Message> lTest = _Collection.Find(filterDef).ToList();
            return await _Collection.Find(filterDef).ToListAsync();
        }

BuildFilter(查询字符串分析)

public static FilterDefinition<Message> BuildFilterDef(IQueryCollection iRequest)
            {
                FilterDefinitionBuilder<Message> builder = Builders<Message>.Filter;
                //var testhardCodedQuery = (builder.Eq("field1", "1") & builder.Eq("field2", "2"));
    
                FilterDefinition<Message> dynamicQuery = builder.Empty;
                var andFilters = builder.Empty;
    
                foreach (KeyValuePair<string, StringValues> filter in iRequest)
                {
                    if (filter.Value != "")
                    {
                        andFilters &= builder.Eq(filter.Key, filter.Value);
                        dynamicQuery = builder.And(andFilters);
    
                    }
                }
                return dynamicQuery;
            }

这不是仅用于&运算符,需要构建出OR(builder.OR

相关问题