如何在Express中通过引用字段过滤Mongoose查询结果
解决Mongoose中通过ObjectId类型分类ID过滤产品的问题
嘿,我之前也碰到过这个坑!问题出在你从URL传过来的category参数是字符串,但Mongoose的ObjectId字段需要严格的ObjectId类型实例,而且看起来你的参数还被错误解析成了数字(错误里的value:5就是证据,应该是长ID字符串被截断了)。下面给你两个靠谱的解决方案:
方案1:在产品模型里处理参数转换
直接在product.js的查询前置中间件里,把传入的category字符串转成ObjectId,这样就不用改路由了:
const restful = require('node-restful') const mongoose = restful.mongoose const productSchema = new mongoose.Schema({ name: { type: String, required: true }, category: {type: mongoose.Schema.Types.ObjectId, ref: 'CategoryProduct'} }) productSchema.pre('find', function () { const queryParams = this.getQuery() // 检查是否有category查询参数 if (queryParams.category) { try { // 把字符串ID转换成Mongoose的ObjectId queryParams.category = mongoose.Types.ObjectId(queryParams.category) } catch (err) { // 如果ID格式无效,直接设置一个不存在的ObjectId,返回空结果 queryParams.category = mongoose.Types.ObjectId() } } // 保留原有的populate逻辑 this.populate('category') }) module.exports = restful.model('product', productSchema)
方案2:在路由层提前拦截处理
如果你更倾向于把参数处理放在路由层面,也可以给保护路由加个中间件,提前转换参数:
const express = require('express') const auth = require('./auth') const mongoose = require('mongoose') module.exports = function (server) { const protectedApi = express.Router() // 新增参数处理中间件 protectedApi.use((req, res, next) => { if (req.query.category) { try { req.query.category = mongoose.Types.ObjectId(req.query.category) } catch (err) { // 格式不对直接返回错误提示 return res.status(400).json({message: '分类ID格式无效,请传入有效的ObjectId字符串'}) } } next() }) server.use('/api', protectedApi) const Product = require('../api/product/productService') Product.register(protectedApi, '/products') }
为啥之前会报错?
你看到的CastError,是因为node-restful默认把查询参数当成普通类型解析,你的长ID字符串被误处理成了数字5(应该是解析时截断了),Mongoose自然没法把5转换成合法的ObjectId。上面的两种方案都是强制把参数转换成ObjectId实例,或者在格式错误时给出明确反馈。
改完之后,你再调用http://localhost:3003/api/products/?category=5af3ac4372edc6000468d766就能正常返回对应分类的产品了,还能保留populate出来的分类信息~
内容的提问来源于stack exchange,提问作者FrancisGregori
相关产品推荐
相关产品推荐

