# 模块二 基础巩固 MongoDB 问答系统

## 2.5.6 MongoDB -- 问答系统 <a href="#id-256mongodb-wen-da-xi-tong" id="id-256mongodb-wen-da-xi-tong"></a>

* MongoDB 数据库设计
* API 实现概述

### MongoDB 数据库设计 <a href="#mongodb-shu-ju-ku-she-ji" id="mongodb-shu-ju-ku-she-ji"></a>

设计优化

* 内嵌（mongo）还是引用（mysql）
* 数据一致性

范式：将数据分散到不同的集合；反范式：使用内嵌文档

在范式化的情况下需要在进行多次查询再拼装数据，或者使用 lookup，即跨表查询；反范式化的情况下可以直接查出相关数据

| 更适合内嵌            | 更适合引用       |
| ---------------- | ----------- |
| 子文档较小            | 子文档较大       |
| 数据不会定期改变         | 数据经常改变      |
| 最终数据一致即可         | 中间阶段数据必须一致  |
| 文档数据小幅增加         | 文档数据大幅增加    |
| 数据通过需要执行二次查询才能获得 | 数据通常不包含在结果中 |
| 快速读取             | 快速写入        |

需求

* 查询所有问题（根据标签查询，按发布时间，浏览数量、投票数量、降序排序）
* 创建问题，回答问题
* 对问题投票，对答案投票
* 对问题添加评论，对答案添加评论
* 对问题进行修改，对答案进行修改
* 我投过票的问题，我投过票的答案
* 我浏览过的问题
* 我回答的问题列表

### API 实现概述 <a href="#api-shi-xian-gai-shu" id="api-shi-xian-gai-shu"></a>

postman 文档：<https://documenter.getpostman.com/view/4874930/TVYM3F2M#4e7e4e11-c424-41ce-a463-3d1995a78ff8>

| api                             | name      |
| ------------------------------- | --------- |
| GET /api/question               | 查询问题列表    |
| GET /api/question/{id}          | 查询单个问题    |
| GET /api/question/{id}/answers  | 查询单个问题带答案 |
| POST /api/question              | 创建问题      |
| PATCH /api/question/{id}        | 修改问题      |
| POST /api/question/{id}/answer  | 回答问题/添加答案 |
| POST /api/question/{id}/up      | 向上投票问题    |
| POST /api/question/{id}/down    | 向下投票问题    |
| POST /api/question/{id}/comment | 添加问题评论    |
| GET /api/answer                 | 查询答案      |
| POST /api/answer/{id}/up        | 向上投票答案    |
| POST /api/answer/{id}/down      | 向下投票答案    |
| PATCH /api/answer/{id}          | 修改答案      |
| POST /api/answer/{id}/comment   | 添加答案评论    |

#### 创建文档类 <a href="#chuang-jian-wen-dang-lei" id="chuang-jian-wen-dang-lei"></a>

* question
* answer
* vote
* comment
* view

```
namespace LighterApi.Data.Question
{
    public class Question : Entity
    {
        public String ProjectId { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public List<string> Tags { get; set; } = new List<string>();

        public int ViewCount { get; set; }

        public int VoteCount { get; set; }

        public List<string> VoteUps { get; set; } = new List<string>();

        public List<string> VoteDowns { get; set; } = new List<string>();

        public List<string> Answers { get; set; } = new List<string>();

        public List<Comment> Comments { get; set; } = new List<Comment>();
    }
}
```

```
namespace LighterApi.Data.Question
{
    public class Answer : Entity
    {
        public string QuestionId { get; set; }

        public string Content { get; set; }

        public int VoteCount { get; set; }

        public List<string> VoteUps { get; set; } = new List<string>();

        public List<string> VoteDowns { get; set; } = new List<string>();

        public List<Comment> Comments { get; set; } = new List<Comment>();
    }
}
```

```
namespace LighterApi.Data.Question
{
    public class Vote : Entity
    {
        public string SourceType { get; set; }

        public string SourceId { get; set; }

        public EnumVoteDirection Direction { get; set; }
    }
}
```

```
namespace LighterApi.Data.Question
{
    public class Comment
    {
        public string Content { get; set; }

        public DateTime CreatedAt { get; set; }

        public string CreatedBy { get; set; }
    }
}
```

```
namespace LighterApi.Data.Question
{
    public class View : Entity
    {
        public string QuestionId { get; set; }
    }
}
```

```
namespace LighterApi.Share
{
    public class ConstVoteSourceType
    {
        public const string Question = "question";

        public const string Answer = "answer";
    }
}
```

```
namespace LighterApi.Share
{
    public enum EnumVoteDirection
    {
        Up = 1,
        Down = 0,
    }
}
```

#### 集成 mongo db driven <a href="#ji-cheng-mongodbdriven" id="ji-cheng-mongodbdriven"></a>

* 安装 nuget 包
* 服务注入 IMongoClient
* 连接字符串

**安装 nuget 包**

```
dotnet package install MongoDB.Driver
```

**服务注入 IMongoClient**

Startup

```
services.AddSingleton<IMongoClient>(sp =>
{
    return new MongoClient(Configuration.GetConnectionString("LighterMongoServer"));
});
```

appsettings.json

```
"LighterMongoServer": "mongodb://127.0.0.1"
```

**连接字符串**

```
连接到单个实例，默认127.0.0.1:27017
var client = new MongoClient();


指定一个连接字符串
var client = new MongoClient("mongodb://localhost:27017");


指写带密码的连接字符串
var client = new MongoClient("mongodb://admin:password@localhost:27017");


连接到一个副本集，客户端服务发现 
var client = new MongoClient("mongodb://localhost:27017,localhost:27018,localhost:27019"
```

### GitHub源码链接： <a href="#github-yuan-ma-lian-jie" id="github-yuan-ma-lian-jie"></a>

<https://github.com/MingsonZheng/ArchitectTrainingCamp/tree/main/LighterApi>
