我要实现的目标是在客户端上构建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形式的网址,但无法正常工作...
任何帮助将不胜感激!
答案 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}" ]
}