C# MongoDB Driver:基于动态集合名关联查询TabA数据的问题
动态集合名关联查询的解决方案
1. 调整数据模型(推荐方案)
MongoDB聚合框架中$lookup的from字段不支持动态引用文档字段,最稳妥的解决方式是调整数据结构:把所有分散的cart/lobId=xxx集合合并成统一的carts集合,给每个购物车文档添加lobId字段用于关联。
这样就能用标准Lookup完成关联查询,代码示例:
// 定义实体类 public class TabA { public ObjectId Id { get; set; } public string LobId { get; set; } // 其他业务字段 } public class Cart { public ObjectId Id { get; set; } public string LobId { get; set; } // 购物车字段 } public class TabAWithCart : TabA { public List<Cart> CartData { get; set; } } // 聚合查询代码 var pipeline = new BsonDocument[] { new BsonDocument("$lookup", new BsonDocument { { "from", "carts" }, { "localField", "LobId" }, { "foreignField", "LobId" }, { "as", "CartData" } }) }; var result = await tabACollection.Aggregate<TabAWithCart>(pipeline).ToListAsync();
该方案符合MongoDB设计理念,查询效率最高,也便于后续维护。
2. 客户端层面优化遍历查询(无法改模型时)
如果不能调整数据模型,可以优化现有遍历逻辑,减少重复查询和开销:
分组批量查询(减少集合连接次数)
先查询所有TabA数据,按lobId分组,同一个lobId对应的集合只查询一次:
var tabAList = await tabACollection.Find(_ => true).ToListAsync(); // 按lobId分组,避免重复查询同一集合 var lobIdGroups = tabAList.GroupBy(t => t.LobId).ToList(); var cartMap = new Dictionary<string, List<Cart>>(); foreach (var group in lobIdGroups) { var cartCollection = database.GetCollection<Cart>($"cart/lobId={group.Key}"); cartMap[group.Key] = await cartCollection.Find(_ => true).ToListAsync(); } // 给每条TabA数据绑定对应的购物车数据 foreach (var tabA in tabAList) { cartMap.TryGetValue(tabA.LobId, out var carts); tabA.CartData = carts ?? new List<Cart>(); }
并行查询(缩短总耗时)
如果TabA数据量不大,可以用并行任务同时查询多个集合,减少总等待时间:
var tabAList = await tabACollection.Find(_ => true).ToListAsync(); var tasks = tabAList.Select(async tabA => { var cartCollection = database.GetCollection<Cart>($"cart/lobId={tabA.LobId}"); tabA.CartData = await cartCollection.Find(_ => true).ToListAsync(); return tabA; }); var result = await Task.WhenAll(tasks);
注意:数据量大时要控制并发数,避免给数据库造成压力,可以用SemaphoreSlim限制并发。
3. 服务器端JavaScript函数(不推荐)
MongoDB 4.4+支持在聚合中用$function执行JavaScript动态查询集合,但这种方式性能差、有安全风险,仅作参考:
var pipeline = new BsonDocument[] { new BsonDocument("$addFields", new BsonDocument( "cartCollection", new BsonDocument("$concat", new BsonArray{"cart/lobId=", "$LobId"}) )), new BsonDocument("$addFields", new BsonDocument( "CartData", new BsonDocument("$function", new BsonDocument { {"body", @"function(colName) { return db.getCollection(colName).find().toArray(); }"}, {"args", new BsonArray{"$cartCollection"}}, {"lang", "js"} }) )) }; var result = await tabACollection.Aggregate<TabAWithCart>(pipeline).ToListAsync();
内容的提问来源于stack exchange,提问作者Allex VO
相关产品推荐
相关产品推荐

