Mongoose find查询如何过滤返回结果中answers数组内的空对象
问题场景
当前执行如下Mongoose查询代码:
const response = await simpleSurveyResponsesModel .find({ "metaKey.projectId": 7, }) .select([ "answers.SEC.text", "answers.S4.text", "answers.S3_a.text", "answers.Urban_City.text" ]) .lean();
其中answers字段为对象数组,数组中同时存在空对象与非空对象。
问题描述
使用collection.find()查询时,指定select的字段会正常返回,但answers数组中会同时返回不需要的空对象。
当前实际输出示例:
{ "_id": "61840979fcbea215bc61ed03", "answers": [ {}, {}, { "Urban_City": { "text": "Hyderabad" } } ] }
期望输出为过滤掉answers数组内空对象的结果,仅保留非空对象条目,示例如下:
{ "_id": "61840979fcbea215bc61ed03", "answers": [ { "Urban_City": { "text": "Hyderabad" } } ] }
需要实现查询约束,让find返回结果的数组字段仅包含非空对象,排除空对象条目。
解决方案
提供两种可落地的实现方式,可根据业务场景选择:
方案1:数据库层面聚合过滤(推荐,性能更优)
通过MongoDB聚合管道的$filter操作符直接在查询阶段完成数组过滤,不会返回冗余空对象数据,适合数据量较大的场景。
const response = await simpleSurveyResponsesModel.aggregate([ // 匹配原有查询条件 { $match: { "metaKey.projectId": 7 } }, { $project: { answers: { $filter: { input: { // 先映射数组,仅保留原有select指定的字段 $map: { input: "$answers", as: "ans", in: { "SEC.text": "$$ans.SEC.text", "S4.text": "$$ans.S4.text", "S3_a.text": "$$ans.S3_a.text", "Urban_City.text": "$$ans.Urban_City.text" } } }, as: "filteredAns", // 过滤条件:保留存在目标字段的非空对象 cond: { $or: [ { $ne: ["$$filteredAns.SEC", undefined] }, { $ne: ["$$filteredAns.S4", undefined] }, { $ne: ["$$filteredAns.S3_a", undefined] }, { $ne: ["$$filteredAns.Urban_City", undefined] } ] } } } } } ])
方案2:查询结果内存过滤(实现简单)
如果业务数据量小,不需要额外优化查询性能,可以保留原有find查询逻辑,在拿到返回结果后遍历过滤空对象,代码改动量最小。
const response = await simpleSurveyResponsesModel .find({ "metaKey.projectId": 7, }) .select([ "answers.SEC.text", "answers.S4.text", "answers.S3_a.text", "answers.Urban_City.text" ]) .lean(); // 遍历结果过滤answers数组中的空对象 const filteredResult = response.map(item => ({ ...item, answers: item.answers.filter(ans => Object.keys(ans).length > 0) }))
内容的提问来源于stack exchange,提问作者Haseeb Sheikh
相关产品推荐
相关产品推荐

