如何编写正确的MongoDB聚合查询以提取书架并排除空响应
问题分析与解决方案
你的核心需求是获取指定书架的所有文档,无论其是否包含目标书籍,但原查询存在几个关键问题:
$unwind默认会丢弃books为空数组的文档,导致空书架记录丢失- 字段名
books.name多了尾部空格,无法匹配正确字段 - 条件逻辑冗余且存在语法错误(
$nin接收数组参数,单个值应使用$ne)
方案1:直接获取指定书架的所有文档
如果只是要保留指定书架的完整文档(包含所有书籍或空数组),不需要后续的拆分和过滤,单个$match即可实现:
let query = [ {$match: {shelf: shelf}} ];
方案2:保留书架文档,同时过滤出目标书籍
如果需要在返回的文档中,单独提取出书架里的目标书籍(没有则为空数组),使用$filter替代$unwind:
let query = [ {$match: {shelf: shelf}}, {$addFields: { targetBooks: { $filter: { input: "$books", cond: {$eq: ["$$this.name", name]} } } }} ];
这样会新增一个targetBooks字段,仅包含名称匹配的书籍,原books字段会被保留。
方案3:使用$unwind但保留空书架文档
如果必须拆分书籍数组处理,需给$unwind添加preserveNullAndEmptyArrays: true参数,同时修正字段和条件:
let query = [ {$match: {shelf: shelf}}, {$unwind: {path: "$books", preserveNullAndEmptyArrays: true}}, {$match: { $or: [ {"books.name": {$exists: false}}, // 匹配空书架的情况 {"books.name": name}, // 匹配目标书籍 {"books.name": {$ne: name}} // 匹配非目标书籍 ] }} ];
如果需要将拆分后的书籍重新聚合为数组,可追加$group阶段:
let query = [ {$match: {shelf: shelf}}, {$unwind: {path: "$books", preserveNullAndEmptyArrays: true}}, {$match: { $or: [ {"books.name": {$exists: false}}, {"books.name": name}, {"books.name": {$ne: name}} ] }}, {$group: { _id: "$_id", shelf: {$first: "$shelf"}, books: {$push: "$books"} }} ];
内容的提问来源于stack exchange,提问作者sair
相关产品推荐
相关产品推荐

