mongodb 文档结构设计
需求: mongodb 记录用户搜索日志并提供用户和管理后台查询
query+qty 唯一
用户端需要展示一个这样的表格:
query (搜索型号) | qty (搜索数量) | weekly_search_times (最近 7 天搜索次数) | last_search_time (最近搜索时间) |
---|---|---|---|
型号 1 | 1 | 10 | 2022-10-13 00:00:00 |
型号 1 | 2 | 4 | 2022-10-18 00:00:00 |
型号 2 | 3 | 4 | 2022-10-18 01:00:00 |
开始是设计这样的结构,之前没怎么用过 mongo ,就用了这种扁平化的结构。
{
"_id": xxx,
"query": "xxx",
"user": 1,
"qty": 100
}
这种当然是最简单方便的,但是领导说不行,这样还不如用 mysql ,这样的化存储的数据量大,后期查询会慢。说要设计一种结构,最好是一个用户一个文档,这个文档除了放用户的搜索历史,后面还可能放一些其他日志类的数据。 但是一个 mongo 文档又有 16M 的大小限制,说是设置一个容量,如果最多存 1000 个搜索日志,超过了清除。于是就有了下面这种结构:
{
"_id": xxx,
"user": 1000,
"search_history": [{"query": "xxx", "time": 1660000, "qty": 1}]
}
这样子呢,相对上一种方法大大减少了文档数,一个用户一个文档,查询效率貌似变高了,因为只要查到一个文档就行,但是查询时无法直接对 search_history 进行过滤, 要把整个文档查询出来然后在内存中实现过滤(时间筛选)、分组( group by query+qty )、分页。 而且查询某个搜索词被哪些用户搜索过不方便实现。 所以这种方案不行。
搜索接口的访问量挺大的,所以是这个日志是写多读少的情况。
所以应该设计怎样的一个结构较为合理,各位大佬赐教。
1
naijoag OP {
"_id": xxx, "query": "xxx", "user": 1, "qty": 100 } 少了一个 time 字段(时间戳)这样的结构也是需要在代码中操作的 开始不知道前端需要展示那样的一个表格(数据要聚合) |
2
naijoag OP 用户端:需要查询时间范围内的日志 (时间范围是日期)
|
3
AS4694lAS4808 2022-10-18 22:56:30 +08:00
如果是哪些词被用户搜索过,应该一个词一个文档?这个文档包含搜索过的用户的 id ?去重或者不去重?
mysql 用关系表+索引搜索也很快。 另外第一种方式查询起来性能还可以,除非真有上千万的用户每天查 N 次。。 |
4
naijoag OP @AS4694lAS4808 意思是再弄一个集合:一个词一个文档 用来满足后台的需求吗
第一种我是觉得还可以 倒没有那么多用户 但是领导说就是第一种方式的话就没必要用 mongo 了 因为 mysql 也可以实现 |
5
wxf666 2022-10-19 00:16:52 +08:00
数据库新手求问,为嘛不能用 MySQL 呢?如果用 MySQL ,这种表结构行不行:
搜索日志表( 用户 ID INT ,时间 TIMESTAMP ,型号 TINYTEXT ,数量 INT , PRIMARY KEY (用户 ID ,时间,型号,数量), INDEX (型号,数量) ) 理由: 1. 每个用户搜索的内容,会尽量聚集在几页(有点类似『一个用户一个文档』),并按时间排序(尽量顺序插入),方便用户端按时间搜索(分组只能临时计算。但问题不大,反正一个用户一段时间内应该也没多少数据) 2. 后台查询某关键词被谁搜索过,走索引也很快 |
6
lithiumii 2022-10-19 00:23:06 +08:00 via Android
查询时可以过滤的,你搜搜 mongo 的 query 怎么写
|
7
caotian 2022-10-19 00:26:48 +08:00
$elemMatch
|
8
naijoag OP |
10
w07128597 2022-10-19 13:08:38 +08:00 via iPhone
第二种方法几年前用过,存的用户的消息记录,可以不用全查出来在内存中筛选分页的,mongodb 自带的函数可以实现
|
12
AS4694lAS4808 2022-10-19 14:16:39 +08:00
@naijoag 要只是为了搜索这个功能启用 mongo 我觉得没必要。。增加了项目复杂度
如果非要用 mongo ,就是一个词一个文档,每次更新用户的 id 和查询时间之类的,甚至对用户 id 去重和时间排序(用户少可以在内存里干,用户多就得用 mongo 函数) |
13
w07128597 2022-10-19 18:44:12 +08:00 via iPhone
@naijoag 不是一个函数,也是类似于 9 楼的多个操作合集,具体我也忘了,好几年了,不过我当时全部是用 mongodb 本身的功能实现的,查询效率确实高
|
14
naijoag OP 目前利用 aggregate ,pipline 里面经历了 objectToArray 和 unwind 两次实现了如下转换。不知道你说的是不是也是这样。
```javascript { "_id": 10000, "search_history": { "query1": [{"qty": 1, "time": 1666185797}, {"qty": 2, "time": 1666185798}] } } ``` ===> ```javascript [ {"_id": 10000, "qty": 1, "time": 1666185797}, {"_id": 10000, "qty": 2, "time": 1666185798} ] ``` |