在MongoDB的查询中,$elemMatch不会将条件视为逻辑与运算符

后端开发 2026-07-09

我基于属性模式设计了一个产品模式。目标是让用户能够使用不同参数查询数据。

产品模式:

const AttributeSchema = new Schema({
  k: { type: String, required: true },
  v: { type: Schema.Types.Mixed, required: true }, 
}, { _id: false });

const ProductSchema = new Schema({
  title: { type: String, required: true },
  category:{ type: String, required: true },
  specs: [AttributeSchema] // Applying the Attribute Pattern here
});

ProductSchema.index({ "specs.k": 1, "specs.v": 1 });
const Product=new model('Product',ProductSchema);
module.exports=Product;

产品路由:

router.get('/api/product', async (req, res) => {
const { key, value } = req.query;
const products = await Product.find({
      specs: { $elemMatch: { k: key, v: value } }
    });
});

MongoDB中的示例存储数据

{
        "title": "shoe1",
        "category": "shoe",
        "specs": [
            {
                "k": "color",
                "v": "red"
            },
            {
                "k": "brand",
                "v": "nike"
            }
        ],
},
{
        "title": "shoe2",
        "category": "shoe",
        "specs": [
            {
                "k": "color",
                "v": "red"
            },
            {
                "k": "brand",
                "v": "adidas"
            }
        ],
}

例如,用户的查询如下:

/api/product?key=brand&value=adidas&key=color&value=red

查询返回与至少一个条件匹配的所有文档。它本应只返回阿迪达斯的鞋款,但由于与条件 color = "red" 匹配,耐克的鞋款也被返回。看起来查询在对 $elemMatch 采用了“或”条件,而不是“且/并且”条件。

下面的代码通过使用 "$and" 运算符来解决这个问题,但我不想在代码中指定任何属性、搜索参数和条件,因为它应该在用户执行查询时由查询参数动态指定。

临时解决方案:

const products = await Product.find( { $and: [
  { specs : { $elemMatch : { k: "brand", v: "adidas" }  } },
{ specs : { $elemMatch : { k: "color", v: "red" }  } }
]});

感谢你的帮助。

解决方案

问题出在查询构造上。这段代码适用于单个键/值对,但当传入多个 keyvalue 参数时,req.query.keyreq.query.value 将变成数组。一个 $elemMatch 不能匹配 specs 数组中的多种不同对象。你需要为每个键/值对构建一个 $elemMatch,并使用 $and 将它们组合起来。

router.get('/api/product', async (req, res) => {
  const keys = Array.isArray(req.query.key) ? req.query.key : [req.query.key];
  const values = Array.isArray(req.query.value) ? req.query.value : [req.query.value];

  const products = await Product.find({
    $and: keys.map((k, i) => ({
      specs: {
        $elemMatch: {
          k: k,
          v: values[i]
        }
      }
    }))
  });

  res.json(products);
});
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章