【问题标题】:Using $elemMatch in projection field - not filtering as desired在投影字段中使用 $elemMatch - 不按需要过滤
【发布时间】:2014-01-19 13:35:54
【问题描述】:

此架构:

var Order = new Schema({
  name: String,
  products: [{
    product: {
     type: Schema.Types.ObjectId,
     ref: "Product"
    },
    qty: Number
  }]
 });

我想查找并返回仅包含具有匹配 ID 的产品的订单。我在 $elemMatch 的尝试没有成功,并且似乎退回了所有产品的整个订单。我可以使用位置运算符 ($),但在这种情况下我想专门使用 $elemMatch。

请注意,订单中的每个产品都是唯一的(在该订单中)

这将返回所有产品:

Order.find({ _id: req.params.id}, { 'products.product': {$elemMatch: { _id: req.params.product }}}, function(err, order) {

这返回空:

Order.find({ _id: req.params.id}, { 'products': {$elemMatch: { 'product._id': req.params.product }}}, function(err, order) {

什么是正确的语法?我希望退回的订单仅包含一件(匹配的)产品。

【问题讨论】:

  • 可能是#code Order.find({ _id: req.params.id,'products.product._id': req.params.product}, { 'products.$' : 1} }}, function(err, order) { #code。但它只检索 products 数组中最大的一个(第一个找到的)产品。如果一个 Order 包含多个相同的产品,它将只返回一个。唯一的方法这样做是通过使用聚合。在聚合中使用 $unwind 操作,然后是 $match

标签: javascript node.js mongodb mongoose


【解决方案1】:

products数组中,product字段直接包含产品的id,所以正确的语法应该是:

Order.find(
    { _id: req.params.id}, 
    { products: {$elemMatch: { product: req.params.product }}}, 
    function(err, order) { ... });

【讨论】:

  • 这几乎没有返回任何内容。这是它返回的内容:[ { _id: 007d0000b10000000000000c, products: [] } ]
  • 实际上等等...我为每个产品都有 2 个 id - 一个用于“产品”,一个是 Mongo 分配给产品下的对象的一个​​ - 我可能把它们弄混了
【解决方案2】:

您只能使用查询投影,如果订单中的产品始终是唯一的(1 个订单中的相同产品不能超过 1 个)。如果同一产品在 1 个订单中出现多个,则不能使用查询投影,因为它只会返回 products 数组中找到的第一个产品。

改为使用聚合。使用 $unwind 和 $match 运算符。 在 mongo shell javascript 中会是这样的。

db.orders.aggregate([
    {$match: {_id: Order_id_being_search}},
    {$unwind: "$products"}, 
    {$match: {"products.product._id": Product_id_being_search }}
])

它将在选定的订单文档中返回所需的产品(仅产品)。如果您想从所有 Order 中返回所需的产品,只需省略第一个 $match。

抱歉,我不习惯使用“REF”,所以我假设在上面的代码中使用 _id 键手动引用。您可以在代码中修改该部分。你可以使用算法。

MongoDB 使用聚合不仅可以找到 sum、avg、max 等聚合值,还可以像关系值一样查找聚合值。它还使用聚合框架来处理子文档。您的案例是聚合框架中 $unwind 操作用例的完美示例。

【讨论】:

  • 我稍微改述了我的问题 - 我确实想退回订单,但我只想要订单中的一种产品。根据文档,我相信 $elemMatch 就是我所需要的,但是..
  • 好吧,我的错。很抱歉我把你引向了错误的方向。很高兴你已经得到了答案..
猜你喜欢
  • 2022-01-14
  • 1970-01-01
  • 2015-05-26
  • 2014-10-21
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多