2.5.7 MongoDB -- API实现

  • 问题查询单个实现
  • 问题查询列表实现
  • 问题跨集合查询实现
  • 问题创建实现
  • 问题更新实现
  • 问题回答实现
  • 问题评论实现
  • 问题投票实现
  • 回答实现

QuestionController

  1. namespace LighterApi.Controller
  2. {
  3. [ApiController]
  4. [Route("api/[controller]")]
  5. public class QuestionController : ControllerBase
  6. {
  7. private readonly IMongoCollection<Question> _questionCollection;
  8. private readonly IMongoCollection<Vote> _voteCollection;
  9. private readonly IMongoCollection<Answer> _answerCollection;
  10. public QuestionController(IMongoClient mongoClient)
  11. {
  12. var database = mongoClient.GetDatabase("lighter");
  13. _questionCollection = database.GetCollection<Question>("questions");
  14. _voteCollection = database.GetCollection<Vote>("votes");
  15. _answerCollection = database.GetCollection<Answer>("answers");
  16. }
  17. }
  18. }

问题查询单个实现

linq 查询

  1. [HttpGet]
  2. [Route("{id}")]
  3. public async Task<ActionResult<Question>> GetAsync(string id, CancellationToken cancellationToken)
  4. {
  5. var question = await _questionCollection.AsQueryable()
  6. .FirstOrDefaultAsync(q => q.Id == id, cancellationToken: cancellationToken);
  7. if (question == null)
  8. return NotFound();
  9. return Ok(question);
  10. }

mongo 查询表达式

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

构造空查询条件的表达式

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

多段拼接 filter

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

问题查询列表实现

  • 数据 AnyIn查询
  • 排序 sort : StirngFieldDefinition
  • 分页 skip, limit
  1. [HttpGet]
  2. public async Task<ActionResult<List<Question>>> GetListAsync([FromQuery] List<string> tags,
  3. CancellationToken cancellationToken, [FromQuery] string sort = "createdAt", [FromQuery] int skip = 0,
  4. [FromQuery] int limit = 10)
  5. {
  6. //// linq 查询
  7. //await _questionCollection.AsQueryable().Where(q => q.ViewCount > 10)
  8. // .ToListAsync(cancellationToken: cancellationToken);
  9. var filter = Builders<Question>.Filter.Empty;
  10. if (tags != null && tags.Any())
  11. {
  12. filter = Builders<Question>.Filter.AnyIn(q => q.Tags, tags);
  13. }
  14. var sortDefinition = Builders<Question>.Sort.Descending(new StringFieldDefinition<Question>(sort));
  15. var result = await _questionCollection
  16. .Find(filter)
  17. .Sort(sortDefinition)
  18. .Skip(skip)
  19. .Limit(limit)
  20. .ToListAsync(cancellationToken: cancellationToken);
  21. return Ok(result);
  22. }

问题跨集合查询实现

  1. [HttpGet]
  2. [Route("{id}/answers")]
  3. public async Task<ActionResult> GetWithAnswerAsync(string id, CancellationToken cancellationToken)
  4. {
  5. // linq 查询
  6. var query = from question in _questionCollection.AsQueryable()
  7. where question.Id == id
  8. join a in _answerCollection.AsQueryable() on question.Id equals a.QuestionId into answers
  9. select new { question, answers };
  10. var result = await query.FirstOrDefaultAsync(cancellationToken);
  11. if (result == null)
  12. return NotFound();
  13. return Ok(result);
  14. }

问题创建实现

  1. [HttpPost]
  2. public async Task<ActionResult<Question>> CreateAsync([FromBody] Question question,
  3. CancellationToken cancellationToken)
  4. {
  5. question.Id = Guid.NewGuid().ToString();
  6. await _questionCollection.InsertOneAsync(question, new InsertOneOptions {BypassDocumentValidation = false},
  7. cancellationToken);
  8. return StatusCode((int) HttpStatusCode.Created, question);
  9. }

问题更新实现

  1. [HttpPatch]
  2. [Route("{id}")]
  3. public async Task<ActionResult> UpdateAsync([FromRoute] string id, [FromBody] QuestionUpdateRequest request,
  4. CancellationToken cancellationToken)
  5. {
  6. if (string.IsNullOrEmpty(request.Summary))
  7. throw new ArgumentNullException(nameof(request.Summary));
  8. var filter = Builders<Question>.Filter.Eq(q => q.Id, id);
  9. var update = Builders<Question>.Update
  10. .Set(q => q.Title, request.Title)
  11. .Set(q => q.Content, request.Content)
  12. .Set(q => q.Tags, request.Tags)
  13. .Push(q => q.Comments, new Comment { Content = request.Summary, CreatedAt = DateTime.Now });
  14. await _questionCollection.UpdateOneAsync(filter, update, cancellationToken: cancellationToken);
  15. return Ok();
  16. }

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

  1. var updateFieldList = new List<UpdateDefinition<Question>>();
  2. if (!string.IsNullOrWhiteSpace(request.Title))
  3. updateFieldList.Add(Builders<Question>.Update.Set(q => q.Title, request.Title));
  4. if (!string.IsNullOrWhiteSpace(request.Content))
  5. updateFieldList.Add(Builders<Question>.Update.Set(q => q.Content, request.Content));
  6. if (request.Tags != null && request.Tags.Any())
  7. updateFieldList.Add(Builders<Question>.Update.Set(q => q.Tags, request.Tags));
  8. updateFieldList.Add(Builders<Question>.Update.Push(q => q.Comments,
  9. new Comment {Content = request.Summary, CreatedAt = DateTime.Now}));
  10. var update = Builders<Question>.Update.Combine(updateFieldList);

问题回答实现

  1. [HttpPost]
  2. [Route("{id}/answer")]
  3. public async Task<ActionResult<Answer>> AnswerAsync([FromRoute] string id, [FromBody] AnswerRequest request,
  4. CancellationToken cancellationToken)
  5. {
  6. var answer = new Answer {QuestionId = id, Content = request.Content, Id = Guid.NewGuid().ToString()};
  7. _answerCollection.InsertOneAsync(answer, cancellationToken);
  8. var filter = Builders<Question>.Filter.Eq(q => q.Id, id);
  9. var update = Builders<Question>.Update.Push(q => q.Answers, answer.Id);
  10. await _questionCollection.UpdateOneAsync(filter, update, null, cancellationToken);
  11. return Ok();
  12. }

问题评论实现

  1. [HttpPost]
  2. [Route("{id}/comment")]
  3. public async Task<ActionResult> CommentAsync([FromRoute] string id, [FromBody] CommentRequest request,
  4. CancellationToken cancellationToken)
  5. {
  6. var filter = Builders<Question>.Filter.Eq(q => q.Id, id);
  7. var update = Builders<Question>.Update.Push(q => q.Comments,
  8. new Comment {Content = request.Content, CreatedAt = DateTime.Now});
  9. await _questionCollection.UpdateOneAsync(filter, update, null, cancellationToken);
  10. return Ok();
  11. }

问题投票实现

  1. [HttpPost]
  2. [Route("{id}/up")]
  3. public async Task<ActionResult> UpAsync([FromBody] string id, CancellationToken cancellationToken)
  4. {
  5. var vote = new Vote
  6. {
  7. Id = Guid.NewGuid().ToString(),
  8. SourceType = ConstVoteSourceType.Question,
  9. SourceId = id,
  10. Direction = EnumVoteDirection.Up
  11. };
  12. await _voteCollection.InsertOneAsync(vote, cancellationToken);
  13. var filter = Builders<Question>.Filter.Eq(q => q.Id, id);
  14. var update = Builders<Question>.Update.Inc(q => q.VoteCount, 1).AddToSet(q => q.VoteUps, vote.Id);
  15. await _questionCollection.UpdateOneAsync(filter, update);
  16. return Ok();
  17. }
  18. [HttpPost]
  19. [Route("{id}/down")]
  20. public async Task<ActionResult> DownAsync([FromBody] string id, CancellationToken cancellationToken)
  21. {
  22. var vote = new Vote
  23. {
  24. Id = Guid.NewGuid().ToString(),
  25. SourceType = ConstVoteSourceType.Question,
  26. SourceId = id,
  27. Direction = EnumVoteDirection.Down
  28. };
  29. await _voteCollection.InsertOneAsync(vote, cancellationToken);
  30. var filter = Builders<Question>.Filter.Eq(q => q.Id, id);
  31. var update = Builders<Question>.Update.Inc(q => q.VoteCount, -1).AddToSet(q => q.VoteDowns, vote.Id);
  32. await _questionCollection.UpdateOneAsync(filter, update);
  33. return Ok();
  34. }

回答实现

  1. namespace LighterApi.Controller
  2. {
  3. [ApiController]
  4. [Route("api/[controller]")]
  5. public class AnswerController : ControllerBase
  6. {
  7. private readonly IMongoCollection<Vote> _voteCollection;
  8. private readonly IMongoCollection<Answer> _answerCollection;
  9. public AnswerController(IMongoClient mongoClient)
  10. {
  11. var database = mongoClient.GetDatabase("lighter");
  12. _voteCollection = database.GetCollection<Vote>("votes");
  13. _answerCollection = database.GetCollection<Answer>("answers");
  14. }
  15. [HttpGet]
  16. public async Task<ActionResult<Answer>> GetListAsync([FromQuery] string questionId, CancellationToken cancellationToken)
  17. {
  18. var list = await _answerCollection.AsQueryable().Where(a => a.QuestionId == questionId)
  19. .ToListAsync(cancellationToken);
  20. return Ok(list);
  21. }
  22. [HttpPatch]
  23. [Route("{id}")]
  24. public async Task<ActionResult> UpdateAsync(string id, string content, string summary,
  25. CancellationToken cancellationToken)
  26. {
  27. var filter = Builders<Answer>.Filter.Eq(q => q.Id, id);
  28. var update = Builders<Answer>.Update
  29. .Set(q => q.Content, content)
  30. .Push(q => q.Comments, new Comment { Content = summary, CreatedAt = DateTime.Now });
  31. await _answerCollection.UpdateOneAsync(filter, update, cancellationToken: cancellationToken);
  32. return Ok();
  33. }
  34. [HttpPost]
  35. [Route("{id}/comment")]
  36. public async Task<ActionResult> CommentAsync([FromRoute] string id, [FromBody] CommentRequest request,
  37. CancellationToken cancellationToken)
  38. {
  39. var filter = Builders<Answer>.Filter.Eq(q => q.Id, id);
  40. var update = Builders<Answer>.Update.Push(q => q.Comments,
  41. new Comment { Content = request.Content, CreatedAt = DateTime.Now });
  42. await _answerCollection.UpdateOneAsync(filter, update, null, cancellationToken);
  43. return Ok();
  44. }
  45. [HttpPost]
  46. [Route("{id}/up")]
  47. public async Task<ActionResult> UpAsync([FromBody] string id, CancellationToken cancellationToken)
  48. {
  49. var vote = new Vote
  50. {
  51. Id = Guid.NewGuid().ToString(),
  52. SourceType = ConstVoteSourceType.Answer,
  53. SourceId = id,
  54. Direction = EnumVoteDirection.Up
  55. };
  56. await _voteCollection.InsertOneAsync(vote, cancellationToken);
  57. var filter = Builders<Answer>.Filter.Eq(q => q.Id, id);
  58. var update = Builders<Answer>.Update.Inc(q => q.VoteCount, 1).AddToSet(q => q.VoteUps, vote.Id);
  59. await _answerCollection.UpdateOneAsync(filter, update);
  60. return Ok();
  61. }
  62. [HttpPost]
  63. [Route("{id}/down")]
  64. public async Task<ActionResult> DownAsync([FromBody] string id, CancellationToken cancellationToken)
  65. {
  66. var vote = new Vote
  67. {
  68. Id = Guid.NewGuid().ToString(),
  69. SourceType = ConstVoteSourceType.Answer,
  70. SourceId = id,
  71. Direction = EnumVoteDirection.Down
  72. };
  73. await _voteCollection.InsertOneAsync(vote, cancellationToken);
  74. var filter = Builders<Answer>.Filter.Eq(q => q.Id, id);
  75. var update = Builders<Answer>.Update.Inc(q => q.VoteCount, -1).AddToSet(q => q.VoteDowns, vote.Id);
  76. await _answerCollection.UpdateOneAsync(filter, update);
  77. return Ok();
  78. }
  79. }
  80. }

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实现)--学习笔记的更多相关文章

  1. .NET 云原生架构师训练营(权限系统 RGCA 开发任务)--学习笔记

    目录 目标 模块拆分 OPM 开发任务 目标 基于上一讲的模块划分做一个任务拆解,根据任务拆解实现功能 模块拆分 模块划分已经完成了边界的划分,边界内外职责清晰 OPM 根据模块拆分画出 OPM(Ob ...

  2. .NET 云原生架构师训练营(权限系统 代码实现 ActionAccess)--学习笔记

    目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.Secu ...

  3. .NET 云原生架构师训练营(权限系统 代码实现 WebApplication)--学习笔记

    目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.WebA ...

  4. .NET 云原生架构师训练营(权限系统 系统演示 ActionAccess)--学习笔记

    目录 模块拆分 环境配置 默认用户 ActionAccess 模块拆分 环境配置 mysql migration mysql docker pull mysql docker run -p 3306: ...

  5. .NET 云原生架构师训练营(权限系统 系统演示 EntityAccess)--学习笔记

    目录 模块拆分 EntityAccess 模块拆分 EntityAccess 实体权限 属性权限 实体权限 创建 student https://localhost:7018/Student/dotn ...

  6. .NET 云原生架构师训练营(权限系统 代码实现 EntityAccess)--学习笔记

    目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.Secu ...

  7. .NET 云原生架构师训练营(权限系统 代码实现 Identity)--学习笔记

    目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.Secu ...

  8. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 问答系统)--学习笔记

    2.5.6 MongoDB -- 问答系统 MongoDB 数据库设计 API 实现概述 MongoDB 数据库设计 设计优化 内嵌(mongo)还是引用(mysql) 数据一致性 范式:将数据分散到 ...

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

    2.5.5 MongoDB -- 聚合 排序 索引类型 创建索引 排序 // 升序 db.getCollection('author').find({}).sort({"age": ...

  10. .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记

    目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...

随机推荐

  1. Jmeter添加事务

    事务 通过第三方工具或jmeter代理录制的脚本,你会发现会录制很多的子请求.比如当打开首页后, 会继续打开图片,css,其他请求等资源文件. 通常我们会剔除掉这些子请求, 但如果我需要衡量打开一个页 ...

  2. flask注册蓝图报错

    记录下这个我找了两天的坑... take no arguments() 这两天一直学习flask的时候,我把注册的蓝图,写成注册的form表单的 举个栗子 class TetsView(view.Me ...

  3. java中的反射(二)

    java中的反射(一):https://www.cnblogs.com/KeleLLXin/p/14060555.html 目录 一.反射 1.class类 2.访问字段 3.调用方法 4.调用构造方 ...

  4. ripple Failed to load resource: the server responded with a status of 404 (Not Found)

    在VS2015中使用Cordova + typescript开发中,遇到个问题. 在javascript console 中提示: Failed to load resource: the serve ...

  5. AtCoder Regular Contest 107(VP)

    Contest Link Official Editorial 比赛体验良好,网站全程没有挂.题面简洁好评,题目质量好评.对于我这个蒟蒻来说非常合适的一套题目. A. Simple Math Prob ...

  6. SQL注入 (一)

    一.手工注入 注入点检测 识别方法:通过在url栏输入'.and 1=1.or 1=1.and sleep(1),如果出现报错,或者页面不一致,则可能存在注入点. 注入类型:整数型.字符型.搜索型.B ...

  7. C++ 虚函数表与多态 —— 多态的简单用法

    首先看下边的代码,先创建一个父类,然后在来一个继承父类的子类,两个类中都有自己的 play() 方法,在代码的第35-37行,创建一个父类指针,然后将子类地址引用赋值给父类,这时调用 P 指针的 pl ...

  8. 从0到1实战移动Web App开发

    从0到1实战移动Web App开发   教程介绍 从0到1 实战webapp,通过热门的web前端技术实现移动端app应用,先基础.后实战,在讲解的同时引导思考,会抛出自己独特的观点,一行一行写代码讲 ...

  9. Redis达到最大占用内存后的淘汰策略

    1. 查询Redis最大占用内存 # 查询最大占用内存 config get maxmemory # 为0时在64操作系统中不限制内存,在32位操作系统中最大为3GB 2. Redis设置最大占用内存 ...

  10. 最全总结 | 聊聊 Python 办公自动化之 PDF(上)

    1. 前言 自动化办公,非 Python 莫属! 从本篇文章开始,我们继续聊聊自动化办公中另外一个常用系列:PPT 2. 准备一下 Python 操作 PPT 最强大的依赖库是:python-pptx ...