.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API实现)--学习笔记

共 10348字,需浏览 21分钟

 ·

2021-01-11 19:49

2.5.7 MongoDB -- API实现

  • 问题查询单个实现

  • 问题查询列表实现

  • 问题跨集合查询实现

  • 问题创建实现

  • 问题更新实现

  • 问题回答实现

  • 问题评论实现

  • 问题投票实现

  • 回答实现

QuestionController

namespace LighterApi.Controller
{
[ApiController]
[Route("api/[controller]")]
public class QuestionController : ControllerBase
{
private readonly IMongoCollection _questionCollection;

private readonly IMongoCollection _voteCollection;

private readonly IMongoCollection _answerCollection;

public QuestionController(IMongoClient mongoClient)
{
var database = mongoClient.GetDatabase("lighter");

_questionCollection = database.GetCollection("questions");
_voteCollection = database.GetCollection("votes");
_answerCollection = database.GetCollection("answers");
}
}
}

问题查询单个实现

linq 查询

[HttpGet]
[Route("{id}")]
public async Task> GetAsync(string id, CancellationToken cancellationToken)
{
var question = await _questionCollection.AsQueryable()
.FirstOrDefaultAsync(q => q.Id == id, cancellationToken: cancellationToken);
if (question == null)
return NotFound();

return Ok(question);
}

mongo 查询表达式

var filter = Builders.Filter.Eq(q => q.Id, id);
await _questionCollection.Find(filter).FirstOrDefaultAsync(cancellationToken);

构造空查询条件的表达式

var filter = string.IsNullOrEmpty(id)
? Builders.Filter.Empty
: Builders.Filter.Eq(q => q.Id, id);

多段拼接 filter

var filter2 = Builders.Filter.And(filter, Builders.Filter.Eq(q => q.TenantId , "001"));

问题查询列表实现

  • 数据 AnyIn查询

  • 排序 sort : StirngFieldDefinition

  • 分页 skip, limit

[HttpGet]
public async Task>> GetListAsync([FromQuery] List<string> tags,
CancellationToken cancellationToken, [FromQuery] string sort = "createdAt", [FromQuery] int skip = 0,
[FromQuery] int limit = 10)
{
//// linq 查询
//await _questionCollection.AsQueryable().Where(q => q.ViewCount > 10)
// .ToListAsync(cancellationToken: cancellationToken);

var filter = Builders.Filter.Empty;

if (tags != null && tags.Any())
{
filter = Builders.Filter.AnyIn(q => q.Tags, tags);
}

var sortDefinition = Builders.Sort.Descending(new StringFieldDefinition(sort));

var result = await _questionCollection
.Find(filter)
.Sort(sortDefinition)
.Skip(skip)
.Limit(limit)
.ToListAsync(cancellationToken: cancellationToken);

return Ok(result);
}

问题跨集合查询实现

[HttpGet]
[Route("{id}/answers")]
public async Task GetWithAnswerAsync(string id, CancellationToken cancellationToken)
{
// linq 查询
var query = from question in _questionCollection.AsQueryable()
where question.Id == id
join a in _answerCollection.AsQueryable() on question.Id equals a.QuestionId into answers
select new { question, answers };

var result = await query.FirstOrDefaultAsync(cancellationToken);

if (result == null)
return NotFound();

return Ok(result);
}

问题创建实现

[HttpPost]
public async Task> CreateAsync([FromBody] Question question,
CancellationToken cancellationToken)
{
question.Id = Guid.NewGuid().ToString();
await _questionCollection.InsertOneAsync(question, new InsertOneOptions {BypassDocumentValidation = false},
cancellationToken);
return StatusCode((int) HttpStatusCode.Created, question);
}

问题更新实现

[HttpPatch]
[Route("{id}")]
public async Task UpdateAsync([FromRoute] string id, [FromBody] QuestionUpdateRequest request,
CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(request.Summary))
throw new ArgumentNullException(nameof(request.Summary));

var filter = Builders.Filter.Eq(q => q.Id, id);

var update = Builders.Update
.Set(q => q.Title, request.Title)
.Set(q => q.Content, request.Content)
.Set(q => q.Tags, request.Tags)
.Push(q => q.Comments, new Comment { Content = request.Summary, CreatedAt = DateTime.Now });

await _questionCollection.UpdateOneAsync(filter, update, cancellationToken: cancellationToken);

return Ok();
}

使用拼接的方式构建表达式

var updateFieldList = new List>();

if (!string.IsNullOrWhiteSpace(request.Title))
updateFieldList.Add(Builders.Update.Set(q => q.Title, request.Title));

if (!string.IsNullOrWhiteSpace(request.Content))
updateFieldList.Add(Builders.Update.Set(q => q.Content, request.Content));

if (request.Tags != null && request.Tags.Any())
updateFieldList.Add(Builders.Update.Set(q => q.Tags, request.Tags));

updateFieldList.Add(Builders.Update.Push(q => q.Comments,
new Comment {Content = request.Summary, CreatedAt = DateTime.Now}));

var update = Builders.Update.Combine(updateFieldList);

问题回答实现

[HttpPost]
[Route("{id}/answer")]
public async Task> AnswerAsync([FromRoute] string id, [FromBody] AnswerRequest request,
CancellationToken cancellationToken)
{
var answer = new Answer {QuestionId = id, Content = request.Content, Id = Guid.NewGuid().ToString()};
_answerCollection.InsertOneAsync(answer, cancellationToken);

var filter = Builders.Filter.Eq(q => q.Id, id);
var update = Builders.Update.Push(q => q.Answers, answer.Id);

await _questionCollection.UpdateOneAsync(filter, update, null, cancellationToken);

return Ok();
}

问题评论实现

[HttpPost]
[Route("{id}/comment")]
public async Task CommentAsync([FromRoute] string id, [FromBody] CommentRequest request,
CancellationToken cancellationToken)
{
var filter = Builders.Filter.Eq(q => q.Id, id);
var update = Builders.Update.Push(q => q.Comments,
new Comment {Content = request.Content, CreatedAt = DateTime.Now});

await _questionCollection.UpdateOneAsync(filter, update, null, cancellationToken);

return Ok();
}

问题投票实现

[HttpPost]
[Route("{id}/up")]
public async Task UpAsync([FromBody] string id, CancellationToken cancellationToken)
{
var vote = new Vote
{
Id = Guid.NewGuid().ToString(),
SourceType = ConstVoteSourceType.Question,
SourceId = id,
Direction = EnumVoteDirection.Up
};

await _voteCollection.InsertOneAsync(vote, cancellationToken);

var filter = Builders.Filter.Eq(q => q.Id, id);
var update = Builders.Update.Inc(q => q.VoteCount, 1).AddToSet(q => q.VoteUps, vote.Id);
await _questionCollection.UpdateOneAsync(filter, update);

return Ok();
}

[HttpPost]
[Route("{id}/down")]
public async Task DownAsync([FromBody] string id, CancellationToken cancellationToken)
{
var vote = new Vote
{
Id = Guid.NewGuid().ToString(),
SourceType = ConstVoteSourceType.Question,
SourceId = id,
Direction = EnumVoteDirection.Down
};

await _voteCollection.InsertOneAsync(vote, cancellationToken);

var filter = Builders.Filter.Eq(q => q.Id, id);
var update = Builders.Update.Inc(q => q.VoteCount, -1).AddToSet(q => q.VoteDowns, vote.Id);
await _questionCollection.UpdateOneAsync(filter, update);

return Ok();
}

回答实现

namespace LighterApi.Controller
{
[ApiController]
[Route("api/[controller]")]
public class AnswerController : ControllerBase
{
private readonly IMongoCollection _voteCollection;

private readonly IMongoCollection _answerCollection;

public AnswerController(IMongoClient mongoClient)
{
var database = mongoClient.GetDatabase("lighter");

_voteCollection = database.GetCollection("votes");
_answerCollection = database.GetCollection("answers");
}

[HttpGet]
public async Task> GetListAsync([FromQuery] string questionId, CancellationToken cancellationToken)
{
var list = await _answerCollection.AsQueryable().Where(a => a.QuestionId == questionId)
.ToListAsync(cancellationToken);
return Ok(list);
}

[HttpPatch]
[Route("{id}")]
public async Task UpdateAsync(string id, string content, string summary,
CancellationToken cancellationToken)
{
var filter = Builders.Filter.Eq(q => q.Id, id);

var update = Builders.Update
.Set(q => q.Content, content)
.Push(q => q.Comments, new Comment { Content = summary, CreatedAt = DateTime.Now });

await _answerCollection.UpdateOneAsync(filter, update, cancellationToken: cancellationToken);

return Ok();
}

[HttpPost]
[Route("{id}/comment")]
public async Task CommentAsync([FromRoute] string id, [FromBody] CommentRequest request,
CancellationToken cancellationToken)
{
var filter = Builders.Filter.Eq(q => q.Id, id);
var update = Builders.Update.Push(q => q.Comments,
new Comment { Content = request.Content, CreatedAt = DateTime.Now });

await _answerCollection.UpdateOneAsync(filter, update, null, cancellationToken);

return Ok();
}

[HttpPost]
[Route("{id}/up")]
public async Task UpAsync([FromBody] string id, CancellationToken cancellationToken)
{
var vote = new Vote
{
Id = Guid.NewGuid().ToString(),
SourceType = ConstVoteSourceType.Answer,
SourceId = id,
Direction = EnumVoteDirection.Up
};

await _voteCollection.InsertOneAsync(vote, cancellationToken);

var filter = Builders.Filter.Eq(q => q.Id, id);
var update = Builders.Update.Inc(q => q.VoteCount, 1).AddToSet(q => q.VoteUps, vote.Id);
await _answerCollection.UpdateOneAsync(filter, update);

return Ok();
}

[HttpPost]
[Route("{id}/down")]
public async Task DownAsync([FromBody] string id, CancellationToken cancellationToken)
{
var vote = new Vote
{
Id = Guid.NewGuid().ToString(),
SourceType = ConstVoteSourceType.Answer,
SourceId = id,
Direction = EnumVoteDirection.Down
};

await _voteCollection.InsertOneAsync(vote, cancellationToken);

var filter = Builders.Filter.Eq(q => q.Id, id);
var update = Builders.Update.Inc(q => q.VoteCount, -1).AddToSet(q => q.VoteDowns, vote.Id);
await _answerCollection.UpdateOneAsync(filter, update);

return Ok();
}
}
}

GitHub源码链接:

https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/LighterApi

课程链接

.NET云原生架构师训练营讲什么,怎么讲,讲多久


欢迎各位读者加入微信群一起学习交流,
在公众号后台回复“加群”即可~~


浏览 30
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报