.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API实现)--学习笔记
2.5.7 MongoDB -- API实现
- 问题查询单个实现
- 问题查询列表实现
- 问题跨集合查询实现
- 问题创建实现
- 问题更新实现
- 问题回答实现
- 问题评论实现
- 问题投票实现
- 回答实现
QuestionController
namespace LighterApi.Controller
{
[ApiController]
[Route("api/[controller]")]
public class QuestionController : ControllerBase
{
private readonly IMongoCollection<Question> _questionCollection;
private readonly IMongoCollection<Vote> _voteCollection;
private readonly IMongoCollection<Answer> _answerCollection;
public QuestionController(IMongoClient mongoClient)
{
var database = mongoClient.GetDatabase("lighter");
_questionCollection = database.GetCollection<Question>("questions");
_voteCollection = database.GetCollection<Vote>("votes");
_answerCollection = database.GetCollection<Answer>("answers");
}
}
}
问题查询单个实现
linq 查询
[HttpGet]
[Route("{id}")]
public async Task<ActionResult<Question>> 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<Question>.Filter.Eq(q => q.Id, id);
await _questionCollection.Find(filter).FirstOrDefaultAsync(cancellationToken);
构造空查询条件的表达式
var filter = string.IsNullOrEmpty(id)
? Builders<Question>.Filter.Empty
: Builders<Question>.Filter.Eq(q => q.Id, id);
多段拼接 filter
var filter2 = Builders<Question>.Filter.And(filter, Builders<Question>.Filter.Eq(q => q.TenantId , "001"));
问题查询列表实现
- 数据 AnyIn查询
- 排序 sort : StirngFieldDefinition
- 分页 skip, limit
[HttpGet]
public async Task<ActionResult<List<Question>>> 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<Question>.Filter.Empty;
if (tags != null && tags.Any())
{
filter = Builders<Question>.Filter.AnyIn(q => q.Tags, tags);
}
var sortDefinition = Builders<Question>.Sort.Descending(new StringFieldDefinition<Question>(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<ActionResult> 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<ActionResult<Question>> 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<ActionResult> UpdateAsync([FromRoute] string id, [FromBody] QuestionUpdateRequest request,
CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(request.Summary))
throw new ArgumentNullException(nameof(request.Summary));
var filter = Builders<Question>.Filter.Eq(q => q.Id, id);
var update = Builders<Question>.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<UpdateDefinition<Question>>();
if (!string.IsNullOrWhiteSpace(request.Title))
updateFieldList.Add(Builders<Question>.Update.Set(q => q.Title, request.Title));
if (!string.IsNullOrWhiteSpace(request.Content))
updateFieldList.Add(Builders<Question>.Update.Set(q => q.Content, request.Content));
if (request.Tags != null && request.Tags.Any())
updateFieldList.Add(Builders<Question>.Update.Set(q => q.Tags, request.Tags));
updateFieldList.Add(Builders<Question>.Update.Push(q => q.Comments,
new Comment {Content = request.Summary, CreatedAt = DateTime.Now}));
var update = Builders<Question>.Update.Combine(updateFieldList);
问题回答实现
[HttpPost]
[Route("{id}/answer")]
public async Task<ActionResult<Answer>> 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<Question>.Filter.Eq(q => q.Id, id);
var update = Builders<Question>.Update.Push(q => q.Answers, answer.Id);
await _questionCollection.UpdateOneAsync(filter, update, null, cancellationToken);
return Ok();
}
问题评论实现
[HttpPost]
[Route("{id}/comment")]
public async Task<ActionResult> CommentAsync([FromRoute] string id, [FromBody] CommentRequest request,
CancellationToken cancellationToken)
{
var filter = Builders<Question>.Filter.Eq(q => q.Id, id);
var update = Builders<Question>.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<ActionResult> 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<Question>.Filter.Eq(q => q.Id, id);
var update = Builders<Question>.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<ActionResult> 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<Question>.Filter.Eq(q => q.Id, id);
var update = Builders<Question>.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<Vote> _voteCollection;
private readonly IMongoCollection<Answer> _answerCollection;
public AnswerController(IMongoClient mongoClient)
{
var database = mongoClient.GetDatabase("lighter");
_voteCollection = database.GetCollection<Vote>("votes");
_answerCollection = database.GetCollection<Answer>("answers");
}
[HttpGet]
public async Task<ActionResult<Answer>> 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<ActionResult> UpdateAsync(string id, string content, string summary,
CancellationToken cancellationToken)
{
var filter = Builders<Answer>.Filter.Eq(q => q.Id, id);
var update = Builders<Answer>.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<ActionResult> CommentAsync([FromRoute] string id, [FromBody] CommentRequest request,
CancellationToken cancellationToken)
{
var filter = Builders<Answer>.Filter.Eq(q => q.Id, id);
var update = Builders<Answer>.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<ActionResult> 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<Answer>.Filter.Eq(q => q.Id, id);
var update = Builders<Answer>.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<ActionResult> 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<Answer>.Filter.Eq(q => q.Id, id);
var update = Builders<Answer>.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

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。
如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。
.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API实现)--学习笔记的更多相关文章
- .NET 云原生架构师训练营(权限系统 RGCA 开发任务)--学习笔记
目录 目标 模块拆分 OPM 开发任务 目标 基于上一讲的模块划分做一个任务拆解,根据任务拆解实现功能 模块拆分 模块划分已经完成了边界的划分,边界内外职责清晰 OPM 根据模块拆分画出 OPM(Ob ...
- .NET 云原生架构师训练营(权限系统 代码实现 ActionAccess)--学习笔记
目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.Secu ...
- .NET 云原生架构师训练营(权限系统 代码实现 WebApplication)--学习笔记
目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.WebA ...
- .NET 云原生架构师训练营(权限系统 系统演示 ActionAccess)--学习笔记
目录 模块拆分 环境配置 默认用户 ActionAccess 模块拆分 环境配置 mysql migration mysql docker pull mysql docker run -p 3306: ...
- .NET 云原生架构师训练营(权限系统 系统演示 EntityAccess)--学习笔记
目录 模块拆分 EntityAccess 模块拆分 EntityAccess 实体权限 属性权限 实体权限 创建 student https://localhost:7018/Student/dotn ...
- .NET 云原生架构师训练营(权限系统 代码实现 EntityAccess)--学习笔记
目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.Secu ...
- .NET 云原生架构师训练营(权限系统 代码实现 Identity)--学习笔记
目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.Secu ...
- .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 问答系统)--学习笔记
2.5.6 MongoDB -- 问答系统 MongoDB 数据库设计 API 实现概述 MongoDB 数据库设计 设计优化 内嵌(mongo)还是引用(mysql) 数据一致性 范式:将数据分散到 ...
- .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 聚合)--学习笔记
2.5.5 MongoDB -- 聚合 排序 索引类型 创建索引 排序 // 升序 db.getCollection('author').find({}).sort({"age": ...
- .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记
目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...
随机推荐
- PyQt(Python+Qt)学习随笔:部件的minimumSize、minimumSizeHint之间的区别与联系
1.minimumSize是一个部件设置的最小值,minimumSizeHint是部件Qt建议的最小值: 2.minimumSizeHint是必须在布局中的部件才有效,如果是窗口,必须窗口设置了布局才 ...
- CentOS下安装SublimeText
1.Install the GPG key: sudo rpm -v --import https://download.sublimetext.com/sublimehq-rpm-pub.gpg 2 ...
- 项目测试环境自动化部署[jenkins前后端配置、Nginx配置]
持续部署:关注点在于项目功能部署到服务器后可以正常运行,为下一步测试环节或最终用户正式使用做准备.(问题点:一个环节有问题,其他环节跟着有问题) 持续集成:关注点是在于尽早发现项目整体运行问题,尽早解 ...
- apache、nginx、Tomcat、IIS引擎解析漏洞
引擎解析漏洞 常见的web容器有IIS.Apache.Nginx.Tomcat等,以下是详细讲解 IIS IIS简介 是 ...
- SP7022 CPATTERN - Cow Patterns
本篇题解用于作者本人加深理解,也欢迎大家阅读. 这道题的正解是\(KMP\)加上树状数组,记录每一个位置前几个位置比其小的.相等的.大的数的数量,比较方式便是比较相应的数量,若相等,则匹配成功. 但是 ...
- 安卓基于谷歌串口api进行串口开发
准备材料 AndroidStudio 谷歌android-serialport-api 前情提要 网上提供很多基于c语言对安卓串口开发,有jni.cmake等等,不过都太高深,谷歌提供的api已经可以 ...
- k8s之yaml文件书写格式
k8s之yaml文件书写格式 1 # yaml格式的pod定义文件完整内容: 2 apiVersion: v1 #必选,版本号,例如v1 3 kind: Pod #必选,Pod 4 metadata: ...
- Tensorflow学习笔记No.11
图像定位 图像定位是指在图像中将我们需要识别的部分使用定位框进行定位标记,本次主要讲述如何使用tensorflow2.0实现简单的图像定位任务. 我所使用的定位方法是训练神经网络使它输出定位框的四个顶 ...
- uniapp云打包配置讲解
HBuilderX开发工具,菜单栏:发行(U) → 原生App云打包(P) 安卓云打包配置: 云打包配置分为公共测试证书和自有证书. 云打包配置使用公共测试证书很简单,直接勾选后打包. 如果要测试第三 ...
- 二、TestNG的Hello World
创建第一个TestNG的例子 1.创建一个TestNG的类 选择项目路径"右键"--NEW--Other 选择TestNG cLass(如果没有这个选项是testng没有配置成功) ...