Mongoose 查询数据过多,导致请求timeout

工作里遇到了个问题,需求方会导出所有数据(csv),而MongoDB因为数据量过大,而导致请求timeOut。

后台用的事node, 后来想到的方法是,自己手动往response里写csv。也就是分批查,查到一批就写一批,这样就不会出现request timeOut的现象了。

代码如下:

module.exports.aggregate_filter_print = (session, keywords, enable, fromDate, endDate, lastModifyInDays, response) => {
    Get.count(EntityDefinition, getFilter(session, keywords, enable, fromDate, endDate, lastModifyInDays)).then(res => {
        const size = 10000;
        const total = res;
        const totalPages = Math.ceil(total / size);
        const fields = ['订单号', '订单名称', '流程卡号', '序号', '产品代码', '产品名称', '规格代码', '规格名称', '数量', '创建时间', '修改时间', '当前工序', '加工人', '是否启用', "上次修改"];
        const opts = { fields };
        const parser = new Parser(opts);
        let filename = encodeURIComponent('流程卡导出') + Moment(fromDate).format('YYYY-MM-DD') + '-' + Moment(endDate).format('YYYY-MM-DD') + '.csv';
        response.set({
            'Content-Type': 'text/csv',
            'Content-Disposition': 'attachment; filename="' + filename + '"'
        });
        UserGet.filterWithoutSession({}, 0, undefined, undefined, true).then(usersRes => {

            Async.timesLimit(totalPages, 1, (number, cb) => {
                this.filter2(session, keywords, enable, fromDate, endDate, lastModifyInDays, number, size).then(filter2Res => {
                    try {
                        var data = filter2Res.map(item => {
                            var currentAction = item.workflow[0].actions.find(action => action.active);
                            if (!currentAction) {
                                currentAction = {}
                            }
                            currentAction.workerUser = usersRes.data.find(user => {
                                return user.id.toString() === currentAction.workerUserId;
                            })
                            if (!currentAction.workerUser) {
                                currentAction.workerUser = {}
                            }
                            return {
                                '订单号': item.manufactureOrderId,
                                '订单名称': item.name || '',
                                '流程卡号': item._id.toString(),
                                '序号': item.batchNumber,
                                '产品代码': item.productCode,
                                '产品名称': item.productName,
                                '规格代码': item.typeCode,
                                '规格名称': item.typeName,
                                '数量': item.quantity,
                                '创建时间': item.createdOn > 0 ? Moment(item.createdOn).format('YYYY-MM-DD HH:mm:ss') : '',
                                '修改时间': item.lastModifiedOn > 0 ? Moment(item.lastModifiedOn).format('YYYY-MM-DD HH:mm:ss') : '',
                                '当前工序': currentAction ? currentAction.name : '',
                                '加工人': (currentAction.workerUser.firstName || '') + (currentAction.workerUser.lastName || ''),
                                '是否启用': item.enable ? '是' : '否',
                                '上次修改': item.lastModifiedOn ? Moment().diff(Moment(item.lastModifiedOn), 'days') + '天前' : ''
                            }
                        })
                        const csv = parser.parse(data);

                        response.write(csv, 'utf-8');
                    } catch (err) {
                        console.error(err);
                    }
                    cb();
                }).catch(err => {
                    console.error(err);
                    cb(err);
                })
            }, (err, results) => {
                if (err) {
                    console.error(err);
                } else {
                    response.end();
                }
            })
        })
    })
}

解释:

Get.count(EntityDefinition, getFilter(session, keywords, enable, fromDate, endDate, lastModifyInDays))

首先是计数,查出所有符合条件的document的数量。

const size = 10000;
const total = res;
const totalPages = Math.ceil(total / size);
let filename = encodeURIComponent(‘流程卡导出’) + Moment(fromDate).format(‘YYYY-MM-DD’) + ‘-’ + Moment(endDate).format(‘YYYY-MM-DD’) + ‘.csv’;
response.set({
‘Content-Type’: ‘text/csv’,
‘Content-Disposition’: ‘attachment; filename="’ + filename + ‘"’
});

第二步是指定每批的批次是多少,算出有多少批次,然后设置response的一些参数,比如Content-Type,返回文件名。

第三步是通过Async.timesLimit方法,循环查询每批次的数据,然后写到response里。

response.write(csv, ‘utf-8’);

循环结束后,调用response.end();,结束请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值