MongoDB查询优化:如何仅返回指定字段以降低服务端负载
MongoDB查询性能优化:仅返回所需字段
用户原始代码
//cat app.get('/cats', function(req, res) { if(!req.session.username) { return res.redirect('/login') } userModel.findOne({ username: req.session.username }).then( (user) => { var newCatArray = []; for(var i = 0; i < user.categoryLinks.length; i++){ newCatArray.push({label: user.categoryLinks[i].label, link: user.categoryLinks[i].link, productLength: user.categoryLinks[i].productLength}) } res.render('cats', {categoryLinks: newCatArray}); } ).catch( (error) => { console.log('Error: ' + error.code + " error: " + error); } ); });
用户问题描述
当前查询返回的用户对象体量较大,结构如下:
{ "email" : "something", "username" : "something", "password" : "something", "categoryLinks" : [ // an array of objects {label: "label", link: "link", productLength: len, links: []}, //links是包含大量对象的数组 .., .., ] }
仅需展示label、link和productLength字段,但数据库会返回categoryLinks[i]中的links对象,增加服务端数据负载。希望直接让数据库返回必要信息,而非在服务端过滤。
优化方案
MongoDB支持**投影(Projection)**来指定仅返回所需字段,不需要使用$match($match用于过滤文档,不是控制返回字段)。直接在findOne的第二个参数中定义投影规则即可:
修改后的代码
//cat app.get('/cats', function(req, res) { if(!req.session.username) { return res.redirect('/login') } // 第二个参数为投影配置:指定需要的字段,排除不需要的字段 userModel.findOne( { username: req.session.username }, { categoryLinks: { label: 1, link: 1, productLength: 1 }, _id: 0 // 排除默认返回的_id字段,如果不需要的话 } ).then( (user) => { // 此时user.categoryLinks已经只包含需要的三个字段,无需再循环处理 res.render('cats', { categoryLinks: user.categoryLinks }); } ).catch( (error) => { console.log('Error: ' + error.code + " error: " + error); } ); });
投影规则说明
字段名: 1:表示要包含该字段字段名: 0:表示要排除该字段- 对于数组中的嵌套对象,直接通过
数组字段.嵌套字段: 1的方式指定要保留的字段,MongoDB会自动过滤数组对象中不需要的属性(比如这里的links会被自动排除)
优化效果
- 减少数据库与服务端之间传输的数据量,提升网络性能
- 省去服务端循环生成新数组的步骤,降低服务端CPU开销
- 直接使用数据库返回的
categoryLinks数据传递给模板,代码更简洁
内容的提问来源于stack exchange,提问作者unbaym
相关产品推荐
相关产品推荐

