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

MongoDB聚合阶段过滤内嵌文档的C#驱动实现问题

MongoDB C# 聚合查询:关联集合并过滤子文档问题解决

我是MongoDB新手,在使用C#驱动执行聚合操作时,面临连接集合并过滤子文档的难题。现有三个集合:SalesRepresentatives、SalesBranches、SalesHistory,我需要获取指定销售代表、其所属分支,以及符合日期筛选条件的最新销售记录。

集合结构

SalesRepresentatives:

{ 
   _id: ObjectId('1234'), 
   FirstName: 'John', 
   LastName: 'Doe', 
   BranchId: ObjectId('1111')
} 

SalesBranches:

{
   _id: ObjectId('1111'), 
   BranchName: 'Branch 1'
}, 
{ 
   _id: ObjectId('1112'), 
   BranchName: 'Branch 2'
}

SalesHistory:

{
   _id: ObjectId('5551'),
   SalesRepresentativeId: ObjectId('1234'),
   SaleDate: '2023-07-26T11:49:46.205+00:00', 
   Amount: 10
},
{
   _id: ObjectId('5552'), 
   SalesRepresentativeId: ObjectId('1234'),
   SaleDate: '2023-07-25T11:49:46.205+00:00', 
   Amount: 11
},
{
   _id: ObjectId('5553'), 
   SalesRepresentativeId: ObjectId('1234'),
   SaleDate: '2023-07-20T11:49:46.205+00:00', 
   Amount: 15
}

期望输出

{ 
   _id: ObjectId('1234'), 
   FirstName: 'John', 
   LastName: 'Doe', 
   SalesBranch: { 
      _id: ObjectId('1111'), 
      BranchName: 'Branch 1'
   }, 
   Sales: [
      { _id: ObjectId('5551'), SaleDate: '2023-07-26T11:49:46.205+00:00', Amount: 10 }, 
      { _id: ObjectId('5552'), SaleDate: '2023-07-25T11:49:46.205+00:00', Amount: 11 }
   ]
}

初始查询代码

DateTime startDate = new DateTime(2023, 07, 25, 0, 0, 0, DateTimeKind.Utc).Date;

var matchFilter = Builders<SalesRepresentative>.Filter.Where(f => f.ID == ObjectId('1234'));
var projFilter = Builders<SalesRepresentative>.Projection.Include(p => p.ID).Include(p => p.FirstName).Include(p => p.LastName).Include(p => p.BranchId);

var pResults = await _mongoDb.SalesRepresentatives.Aggregate() 
   .Match(matchFilter) 
   .Project(projFilter) 
   .Lookup("SalesBranches", "_id", "BranchId", "SalesBranch")
   .Lookup("SalesHistory", "_id", "SalesRepresentativeId", "RecentSales") 
   .Project(new BsonDocument {
      { "_id", 1 }, 
      { "FirstName", 1 }, 
      { "LastName", 1 }, 
      { "SalesBranch._id", 1 }, 
      { "SalesBranch.BranchName", 1 }, 
      { "RecentSales._id", 1 }, 
      { "RecentSales.SaleDate", 1 }
   }).ToListAsync();

该查询可执行,但会返回该销售代表的所有销售记录,我仅需SaleDate >= startDate的记录。

修改后报错的查询代码

var pResults = await _mongoDb.SalesRepresentatives.Aggregate() 
   .Match(matchFilter) 
   .Project(projFilter) 
   .Lookup("SalesBranches", "_id", "BranchId", "SalesBranch")
   .Lookup("SalesHistory", "_id", "SalesRepresentativeId", "RecentSales") 
   .Project(new BsonDocument {
      { "_id", 1 }, 
      { "FirstName", 1 }, 
      { "LastName", 1 }, 
      { "SalesBranch._id", 1 }, 
      { "SalesBranch.BranchName", 1 }, 
      { "Sales", new BsonDocument { 
            { "$filter", new BsonDocument { 
                  { "input", "$RecentSales" }, 
                  { "as", "Sales" }, 
                  { "cond", new BsonDocument {
                        { "$gte", new BsonDocument { 
                              { "$$Sales.SaleDate", startDate }
                           } 
                        }
                     }
                  }
               } 
            }
         }
      }
   }).ToListAsync();

执行后出现异常:

Command aggregate failed: Invalid $project :: caused by :: 'Sales' starts with an invalid character for a user variable name.

解决方案

问题源于$filter的as参数:不能以大写开头,且不能与上层字段名Sales重名,需改为sale;同时需修正日期比较的构造方式。最终可用代码如下:

.Project(new BsonDocument {
   { "_id", 1 }, 
   { "FirstName", 1 }, 
   { "LastName", 1 }, 
   { "SalesBranch._id", 1 }, 
   { "SalesBranch.BranchName", 1 }, 
   { "Sales", new BsonDocument { 
         { "$filter", new BsonDocument { 
               { "input", "$RecentSales" }, 
               { "as", "sale" }, 
               { "cond", new BsonDocument {
                     { "$gte", new BsonArray {
                        startDate, new BsonDocument("$toDate", "$sale.SaleDate")
                        } 
                     }
                  }
               } 
            }
         }
      }
   }).ToListAsync();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 19:42:21