通过URL查询字符串发送mongodb聚合条件

时间:2019-02-21 04:38:18

标签: c# mongodb

我要实现的目标是在客户端上构建MongoDB聚合阶段,然后通过URL查询字符串将其发送到Web API以根据这些条件获得结果。

我正在使用以下网址与邮递员一起使用

http://.../monsters/aggregate?pipes={"$match":{"name":"foo"}, "$max": 2}

在控制器中,我有:

    [HttpGet("aggregate")]
    public async Task<IActionResult> GetByAggregate([FromQuery(Name = "pipes")]string pipes)
    {
        if (!string.IsNullOrEmpty(pipes))
        {
            BsonDocument d = BsonDocument.Parse(pipes);

            var p = PipelineDefinition<T, T>.Create(d);

            IAsyncCursor<T> result = await _monsterService.AggregateAsync(p);

            return Ok(result.ToListAsync());
        }

        return NotFound();
    }

这不起作用,错误消息:

  

MongoCommandException:命令聚合失败:管道阶段规范对象必须恰好包含一个字段。

但是有了这个URL,我就能得到我想要的:

http://.../monsters/aggregate?pipes={"$match":{"name":"foo"}}

如何将mongodb管道解析为url查询字符串的正确json格式,然后反序列化为api上的mongodb管道阶段?

是否有更好的方法可以做到这一点?

我尝试了一些thirdparty形式的网址,但无法正常工作...

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

聚合管道是一个阶段数组,因此,如果要具有灵活的端点,则需要传递一个数组。每个表示单个管道的JSON在根级别只能有一个字段,并且该属性应该表示管道阶段名称,例如$match。这就是为什么您使用$max的示例无法正常工作的原因。

此外,如果您想限制2个对象,则应使用$limit而不是$max(用于聚合数据)。因此,您的聚合管道应如下所示:

[{"$match":{"name":"foo"}},{"$limit":2}]

由于必须将数组而不是单个字符串传递给API,因此使用POST而不是GET端点并在请求的正文中传递该数组会更容易

public class Payload
{
    public string[] Pipes { get; set; }
}

[HttpPost("aggregate")]
public async Task<IActionResult> GetByAggregate([FromBody]Payload payload)
{
    if (!string.IsNullOrEmpty(pipes))
    {
        var p = PipelineDefinition<T, T>.Create(payload.Pipes.Select(BsonDocument.Parse));

        IAsyncCursor<T> result = await _monsterService.AggregateAsync(p);

        return Ok(result.ToListAsync());
    }

    return NotFound();
}

然后您可以发送带有以下正文的POST请求:

{
    "pipes": [ "{\"$match\":{\"name\":\"foo\"}}","{\"$limit\":2}"  ]
}