You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MongoDB中创建匹配嵌套值与父文档值的过滤器?

MongoDB文档内嵌套字段匹配查询问题

示例文档结构

{
   "_id" : (guid),
   "basePrice" : 5000,
   "productCategories" : [{
       "_id" : (Guid),
       "categoryName" : "",
       "isActive" : true,
       "products" : [{
           "_id" : (guid),
           "productCode" : "GoKart",
           "price" : 5000
       }]
   }]
}

查询需求

获取满足以下条件的文档:

  • 存在处于激活状态(isActive: true)的productCategory
  • 该激活分类下存在productCode为"GoKart"的产品,且产品的price等于父文档的basePrice

尝试过的无效写法

1. LINQ Where写法

.Where(
   x => x.ProductCategories.Any(pc =>
               pc.IsActive &&
               pc.Products.Any(p =>
                    p.Type.ShortCode == "GoKart" &&
                    p.Price == x.BasePrice
               )
    )
)

问题:MongoDB驱动不支持在嵌套的Any表达式中引用根文档的x.BasePrice,无法转换为有效查询。

2. FilterBuilder结合$expr的错误写法

filterBuilder.And(                                
   Builders<Inventory>.Filter.ElemMatch(inv => inv.ProductCategorys,                                    
      Builders<ProductCategory>.Filter.And(                                        
         Builders<ProductCategory>.Filter.Eq(pc => pc.IsActive, true),                                        
         Builders<ProductCategory>.Filter.ElemMatch(pc => pc.Products,                                             
            Builders<Product>.Filter.Eq(p => p.ShortCode, "GoKart")
         )
      )
   ),
   Builders<Inventory>.Filter.Eq("$expr",
      Builders<Inventory>.Filter.Eq(
         "$basePrice" ,                                        
         "$ProductCategories.Products.Price"
      )
   )
);   

问题:$ProductCategories.Products.Price是二维数组结构,直接与$basePrice比较永远不相等,且$expr的使用方式不符合MongoDB聚合语法。

正确解决方案

由于需要在文档内部进行跨层级字段比较,必须使用MongoDB的聚合表达式$expr结合数组遍历操作符来实现。

原生MongoDB查询语句

db.inventory.find({
  $expr: {
    $anyElementTrue: {
      $map: {
        input: "$productCategories",
        as: "pc",
        in: {
          $and: [
            "$$pc.isActive",
            {
              $anyElementTrue: {
                $map: {
                  input: "$$pc.products",
                  as: "p",
                  in: {
                    $and: [
                      { $eq: ["$$p.productCode", "GoKart"] },
                      { $eq: ["$$p.price", "$basePrice"] }
                    ]
                  }
                }
              }
            }
          ]
        }
      }
    }
  }
})

对应的C# FilterBuilder实现

var filter = Builders<Inventory>.Filter.Expr(
    new BsonDocument("$anyElementTrue",
        new BsonDocument("$map",
            new BsonDocument
            {
                { "input", "$productCategories" },
                { "as", "pc" },
                { "in",
                    new BsonDocument("$and",
                        new BsonArray
                        {
                            "$$pc.isActive",
                            new BsonDocument("$anyElementTrue",
                                new BsonDocument("$map",
                                    new BsonDocument
                                    {
                                        { "input", "$$pc.products" },
                                        { "as", "p" },
                                        { "in",
                                            new BsonDocument("$and",
                                                new BsonArray
                                                {
                                                    new BsonDocument("$eq", new BsonArray { "$$p.productCode", "GoKart" }),
                                                    new BsonDocument("$eq", new BsonArray { "$$p.price", "$basePrice" })
                                                }
                                            )
                                        }
                                    }
                                )
                            )
                        }
                    )
                }
            }
        )
    )
);

// 执行查询
var matchingDocuments = inventoryCollection.Find(filter).ToList();

逻辑说明

  1. 使用$map遍历外层的productCategories数组,对每个分类判断是否激活
  2. 对激活的分类,再次用$map遍历其products数组,判断产品的productCode是否为"GoKart"且price等于根文档的basePrice
  3. 两层$anyElementTrue确保只要存在任意一个符合条件的分类和产品,文档就会被匹配

内容的提问来源于stack exchange,提问作者Neo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 03:42:48