.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 ...
随机推荐
- HTTP请求头和响应头详解【转】
最近老猿在开始学习爬虫相关的知识,由于老猿以前只做非web的后台应用,发现相关知识太过匮乏,导致学习很困难,为此不得不从一些基础知识恶补开始,对于这些知识,老猿会将网上找到的比较认可的内容直接转发. ...
- Shell命令和流程控制[linux常用命令的使用]
在shell脚本中使用三类命令: unix命令 概念:管道.重定向.backtick 流程控制 1 unix命令 echo "some text":在屏幕上输出信息 ls:文件列表 ...
- 对网页接口的追踪探索(以b站通过bv号查询av号为例
对网页接口的追踪探索(以b站通过bv号查询av号为例 序言 本文只提供一种探索网页加载时后端访问接口情况的思路,所举例子没有太大实际用处. 一 自2020年3月23日起,AV号将全面升级到BV号.但是 ...
- 学习笔记:Link Cut Tree
模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...
- AcWing 361. 观光奶牛
01规划 设答案为 \(ans\). 二分答案,设当前二分值为 \(mid\). 设一个环 \(S\) 的边权为 \(t_1, t_2, t_3...\),点权为 \(f_1, f_2, f_3... ...
- uni-app中组件的使用
组件基本知识点: uniapp中:每个页面可以理解为一个单页面组件,这些单页面组件注册在pages.json里,在组件关系中可以看作父组件. 自定义可复用的组件,其结构与单页面组件类似,通常在需要的页 ...
- mybatis-plus快速入门并使用
目录 mybatis-plus的初次使用总结 说明:官网自有黄金屋,深入学习看官网是必须的,废话不多说 环境:springboot.mysql 一.配置 pom yml配置数据库 二.代码生成器 生成 ...
- jsp+servlet实现美妆店铺开发
一般的商城都有用户端和商城端两个部分,用户端就是给普通用户使用的,像我们在淘宝购物,我们就是使用的用户端:然而淘宝还分了很多个店铺,每个店铺的商品都是店老板安排人员去管理,那店老板管理自己的店铺用到的 ...
- 目前市面上比较流行的devops运维平台汇总
1,spug 1,Spug简介 Spug是面向中小型企业设计的无 Agent的自动化运维平台,整合了主机管理.主机批量执行.主机在线终端.应用发布.任务计划.配置中心.监控.报警等一系列功能.演示地址 ...
- java 系统属性设置
一.语法: java -Dproperty=value 二.注意事项: value如果有空格,需用使用双引号如:java -Dfoo="some string" 三.常见使用地方: ...