这样格式的数据应该是很常见的。
const result = {
list: [{ a: 1 }, { a: 2 }, { a: 3 }],
total: 3,
};
之前我的做法是查 2 次
一次 list, 一次 total。
我想问问有没有办法查一次就出结果的? 求教~
单独的 list 我是这么写的。
const { query = {}, queryPopulate = {}, limit = 10, skip = 0 } = parmas;
const list = await this.ctx.model.Monitor.Check
.aggregate()
.match(query)
.sort({ "meta.createdAt": -1 })
.lookup({
from: 'Project',
localField: 'Project',
foreignField: '_id',
as: 'Project',
})
.addFields({ Project: { $arrayElemAt: ['$Project', 0] } })
.match(queryPopulate)
.skip(limit * skip)
.limit(limit);
1
menyakun 2019-08-11 19:57:18 +08:00
所以 list 和 total 来自两个 collection ?那可不是得查两次
|
2
lqzhgood OP @menyakun 同一个 collection
例如有一组数据 [{a:1},{a:2},{a:3},{a:4},{a:5},{a:6},{a:7},{a:8},{a:9},{a:10}.........,{a:98},{a:99},{a:100}] 前端传过来一个查询条件 a>50 ,需要返回 分页为每页 5 个 第 2 页的数据, 也就是需要返回的数据为 const result = { list: [{a:56},{a:57},{a:58},{a:59},{a:60}], total: 50 } 我之前的做法是 const result = { list: await Model.find( {a:{"$gt":50}} ).skip(1),limit(5), total: await Model.find( {a:{"$gt":50}} ).count() } 这里 find 了两次 query。实际上是查了 2 次数据库。 我想在 find 第一次的时候就计算出 total。然后再 skip limit 返回 list,然后这个很常见的需求, MongoDB 怎么做呢? P.S 我查了 MongoDB 文档, aggregation 里面的 facet 应该是可以做这个需求的。但是我写了一下午也没搞出来。result 始终返回的是一个 Array 不是一个 Object。求教 #api https://docs.mongodb.com/manual/reference/operator/aggregation/facet/ |
3
tankeco 2019-08-11 20:25:13 +08:00 1
大概就这样?
ret = aggregate( {查询条件}, { facet: { "list": [ {$sort: {...}}, {$skip: xxx}, {$limit: xxx} ], "total": [ {$count: "total"} ] } } ) 返回的是 array,你把第一个元素拿出来就行了。 ret = ret[0] if len(ret['total']) == 0: ret['total'] = 0 else: ret['total'] = ret['total'][0]['total'] |
5
lqzhgood OP @menyakun 3Q~
aggregate 只能返回 Array 那就没办法了~ 不过我感觉从语义上来说 facet 以后应该要返回 Object 的。 因为 facet 以后只剩下一个 DIY 后重组的对象了,还不如直接返回这个 Object。 P.S 奇了怪了 我下午也是按 3L 这么写, $count 那里一直报错。 估计是哪里秀逗了~~ |
6
lqzhgood OP 贴一下最终代码留给后人~
let resp = await this.ctx.model.Monitor.Check .aggregate() .match(query) .lookup({ from: 'Project', localField: 'Project', foreignField: '_id', as: 'Project', }) .addFields({ Project: { $arrayElemAt: ['$Project', 0] } }) .match(queryPopulate) .facet({ list: [{ $sort: { "meta.createdAt": -1 } }, { $skip: (page - 1) * limit }, { $limit: limit }], total: [{ $count: "total" }], }) .addFields({ total: { $arrayElemAt: ['$total', 0] } }) .project({ list: 1, total: "$total.total" }); 最后两行是重组 Object 结构的。 如果查询条件为空 total 会返回空数组,最终还要处理 query 到 空数组的 临界情况 resp = resp[0]; if (!resp.total) resp.total = 0; 整体下来感觉补丁打的挺多的 没有酣畅淋漓的感觉~ 如果有更好的写法 欢迎下面回帖补充 |
7
ljpCN 2019-12-24 10:09:59 +08:00
可以用 group 然后用 push 操作符来生成你需要的 list
|