如何使用MongoDB C#驱动匹配包含全部指定角色内嵌文档的用户文档
问题描述
我有一个名为Users的MongoDB集合,文档结构如下:
{ "_id": ObjectId("5ded105e90424e1c0e6fda04"), "username": "user1", "roles": [ {"_id" : ObjectId("3aded105e90424e1c0e6fb542"), "name":"admin"}, {"_id" : ObjectId("5ded105e90424e1c0e6fda05"), "name": "fin"}, ] }, { "_id": ObjectId("5ded105e90424e1c0e6fda05"), "username": "user2", "roles": [ {"_id" : ObjectId("3aded105e90424e1c0e6fb542"), "name":"admin"}, {"_id" : ObjectId("5ded105e90424e1c0e6fda05"), "name":"fin"}, ] }, { "_id": ObjectId("5ded105e90424e1c0e6fda06"), "username": "user3", "roles": [ {"_id" : ObjectId("9bded105e45624e1c0e6fb289"), "name":"basic"}, {"_id" : ObjectId("5ded105e90424e1c0e6fda05"), "name": "fin"}, ] }
需要筛选出roles字段包含指定数组arr = [ObjectId("3aded105e90424e1c0e6fb542"), ObjectId("5ded105e90424e1c0e6fda05")]中所有元素的文档(即同时拥有admin和fin角色的用户,预期结果是user1和user2)。
注意:如果roles是简单的ID数组而非内嵌文档数组,可直接用.All操作符实现:
filter &= Builders<Users>.Filter.All( doc => doc.Roles, Ids)
解决方案
当roles是内嵌文档数组时,需要确保每个指定的角色ID都能在roles数组的某个元素的_id字段中找到,以下两种方式均可实现需求:
方式一:多ElemMatch条件组合
为每个目标角色ID创建一个ElemMatch条件,指定roles数组中存在对应_id的元素,再用And组合所有条件:
var targetRoleIds = new List<ObjectId> { ObjectId.Parse("3aded105e90424e1c0e6fb542"), ObjectId.Parse("5ded105e90424e1c0e6fda05") }; var filterBuilder = Builders<Users>.Filter; var filters = targetRoleIds.Select(id => filterBuilder.ElemMatch(doc => doc.Roles, role => role._id == id) ); var finalFilter = filterBuilder.And(filters); var result = await collection.Find(finalFilter).ToListAsync();
方式二:All操作符结合内嵌字段路径
直接针对roles._id字段使用All操作符,利用MongoDB的字段路径语法简化查询:
var targetRoleIds = new List<ObjectId> { ObjectId.Parse("3aded105e90424e1c0e6fb542"), ObjectId.Parse("5ded105e90424e1c0e6fda05") }; // 强类型写法 var filter = Builders<Users>.Filter.All(doc => doc.Roles[-1]._id, targetRoleIds); // 或直接使用字符串字段路径 // var filter = Builders<Users>.Filter.All("roles._id", targetRoleIds); var result = await collection.Find(filter).ToListAsync();
两种方式都能准确筛选出同时包含所有指定角色ID的用户文档,得到预期的user1和user2。
内容的提问来源于stack exchange,提问作者LightTechnician
相关产品推荐
相关产品推荐

