MongoDB C#中.Match()与.Lookup()方法使用问题求助
MongoDB查询关联邻市数据的语法错误排查
问题描述
作为软件开发新手,正在学习MongoDB,当前遇到技术问题:需要在项目中查询选中城市信息时,同时获取其邻市的车牌代码(PlakaCode)及城市名称。调研后得知需使用.Match()和.Lookup()方法,但编写代码时持续出现语法错误,不确定代码结构是否正确,请求协助排查。
实体类定义
public class RelationalCityViewModel { [BsonId] public ObjectId Id { get; set; } public string PlakaCode { get; set; } public string Name { get; set; } public int OrderNo { get; set; } public bool IsDelete { get; set; } public int CountryId { get; set; } public string Url { get; set; } public List<NeighborCity> NeighborCities { get; set; } }
public class RelationalCityCreateViewModel { public string PlakaCode { get; set; } public string Name { get; set; } public int OrderNo { get; set; } public int CountryId { get; set; } public string Url { get; set; } public List<NeighborCity> NeighborCities { get; set; } } public class NeighborCity { [BsonId] public ObjectId Id { get; set; } public string PlakaCode { get; set; } public string Name { get; set; } public bool IsDelete { get; set; } }
查询方法代码
public async Task<BsonDocument> GetDataByIdWithFilter(FilterDefinition<BsonDocument>? filter, ObjectId id, RelationalCityViewModel relationalCityViewModel) { var result = _mongoDbCollection.Aggregate() .Match(filter) .Lookup(_mongoDbCollection, relationalCityViewModel.NeighborCities.FirstOrDefault().Id, relationalCityViewModel.Id, (RelationalCityViewModel city, IEnumerable<RelationalCityViewModel> neighbors) => new { city.Name, city.PlakaCode, NeighborCities = neighbors.Select(n => new { n.Name, n.PlakaCode }) } ); return result; }
问题排查与修正
你的代码存在3个核心问题,导致语法和逻辑错误:
Lookup参数逻辑错误
MongoDB C#驱动的.Lookup()需要传入字段映射关系,而非具体的ID值。你直接使用relationalCityViewModel.NeighborCities.FirstOrDefault().Id(方法参数的具体值)替代了聚合管道中当前文档的字段路径,完全不符合Lookup的关联逻辑。类型不匹配
方法返回类型是BsonDocument,但聚合操作返回的是匿名类型的集合,类型无法兼容,会触发编译错误。异步操作未正确处理
方法标记了async,但未使用await调用聚合的异步方法,既会触发编译警告,也会导致逻辑上的错误。
修正方案1:分步查询(更直观)
假设_mongoDbCollection是IMongoCollection<RelationalCityViewModel>类型,分步查询逻辑更清晰:
public async Task<RelationalCityViewModel> GetCityWithNeighbors(ObjectId cityId) { // 1. 获取目标城市 var targetCity = await _mongoDbCollection.Find(c => c.Id == cityId && !c.IsDelete).FirstOrDefaultAsync(); if (targetCity == null) return null; // 2. 提取邻市ID并查询对应数据 var neighborIds = targetCity.NeighborCities.Select(n => n.Id).ToList(); var neighborCities = await _mongoDbCollection.Find(c => neighborIds.Contains(c.Id) && !c.IsDelete) .Project(c => new NeighborCity { Name = c.Name, PlakaCode = c.PlakaCode }) .ToListAsync(); // 3. 组装结果 targetCity.NeighborCities = neighborCities; return targetCity; }
修正方案2:聚合管道Lookup实现
如果一定要用聚合管道完成,正确的写法如下:
public async Task<RelationalCityViewModel> GetCityWithNeighborsByAggregate(ObjectId cityId) { var result = await _mongoDbCollection.Aggregate() // 匹配目标城市 .Match(c => c.Id == cityId && !c.IsDelete) // Lookup关联邻市:本地字段是邻市ID列表,关联集合的主键_id .Lookup( foreignCollection: _mongoDbCollection, localField: c => c.NeighborCities.Select(n => n.Id), foreignField: c => c.Id, @as: (RelationalCityViewModel c) => c.NeighborCities ) // 投影只保留需要的字段 .Project(c => new RelationalCityViewModel { Id = c.Id, Name = c.Name, PlakaCode = c.PlakaCode, NeighborCities = c.NeighborCities.Select(n => new NeighborCity { Name = n.Name, PlakaCode = n.PlakaCode }).ToList() }) .FirstOrDefaultAsync(); return result; }
关键注意点
- 确保集合泛型类型为
RelationalCityViewModel,而非BsonDocument,利用强类型映射避免转换错误。 - Lookup的
localField必须是当前文档中存储关联ID的字段路径,foreignField是关联集合的匹配字段(这里是主键_id)。 - 聚合操作必须配合
await调用异步方法,返回类型要与聚合结果匹配。
内容的提问来源于stack exchange,提问作者Kerem Aluç
相关产品推荐
相关产品推荐

