.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API实现)--学习笔记
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
课程链接
评论