如何在mongoose的populate方法中实现类like模糊查询,按用户firstname检索频道
首先修正关联字段类型错误
你当前ChannelSchema中_user字段类型定义为String,但User表的主键是ObjectId类型,会导致关联失效,先调整该字段定义:
const ChannelSchema = new mongoose.Schema({ title: { type: String, require: true, trim: true, unique: true }, _user: { type: mongoose.Schema.Types.ObjectId, // 改为此类型 ref: 'User', // 加上ref指向User模型 require: true, trim: true, unique: true } })
方案1:populate + 结果过滤
populate的match参数可以对关联文档做条件过滤,但要注意:该过滤仅作用于关联文档,不符合条件的关联字段会返回null,你需要再对主查询结果做一次过滤:
// 从搜索框获取的关键词 const searchKeyword = '你要搜索的firstname关键词' // 构造不区分大小写的正则,实现类似SQL的like效果 const reg = new RegExp(searchKeyword, 'i') let ChannelSearch = await Channel .find() .populate({ path: '_user', select:'-password', populate: { path: '_profile', match: { firstname: { $regex: reg } // 对firstname做模糊匹配 } } }) // 过滤掉关联的_profile为空的结果,就是符合条件的频道 ChannelSearch = ChannelSearch.filter(item => item._user?._profile)
方案2:使用aggregate聚合查询(更高效)
该方案会直接在数据库层面过滤出符合条件的频道,不会查询多余的无效数据,性能更好:
const searchKeyword = '你要搜索的firstname关键词' const reg = new RegExp(searchKeyword, 'i') let ChannelSearch = await Channel.aggregate([ // 第一步关联User表 { $lookup: { from: 'users', // User模型对应的表名,默认是模型名小写加s localField: '_user', foreignField: '_id', as: 'userInfo' } }, // 拍平关联返回的数组 { $unwind: '$userInfo' }, // 第二步关联Profile表 { $lookup: { from: 'profiles', // Profile模型对应的表名 localField: 'userInfo._profile', foreignField: '_id', as: 'profileInfo' } }, { $unwind: '$profileInfo' }, // 过滤符合firstname条件的结果 { $match: { 'profileInfo.firstname': { $regex: reg } } }, // 可选:过滤返回字段,去掉不需要的敏感信息 { $project: { title: 1, 'userInfo.email': 1, 'profileInfo.name': 1, 'profileInfo.firstname': 1 } } ])
- 正则的第二个参数
i代表不区分大小写,如果需要区分大小写可以去掉该参数 - 如果需要实现前缀匹配(效果同SQL的
like 'xxx%')可以写成new RegExp('^' + searchKeyword, 'i'),后缀匹配同理写searchKeyword + '$',这种写法可以命中索引性能更高。
内容的提问来源于stack exchange,提问作者alexandre_plt
相关产品推荐
相关产品推荐

