使用 C# 在 MongoDB 集合中嵌入文档的 Where 子句查询中的投影

Projection in Where Clause Query of a Embedded document in MongoDB Collection using C#

Filter the Collection in DB instead of Memory

我有一个模型 Class,将其保存在 MongoDB 集合中,然后按照我下面提到的期望进行查询。

我的模型Class:

public Class Employee
{
    public ObjectId Id { get; set; }
    public string EmpID { get; set; }
    public string EmpName { get; set; }
    public List<Mobile> EmpMobile { get; set; }
    public bool IsLive { get; set; }
}

public Class Mobile
{
    public string MobID { get; set; }
    public string MobNumber { get; set; }
    public bool IsPreferred { get; set; }
    public bool IsLive { get; set; }
}

值为

List<Employee> EmpInfo = new List<Employee>() {
new Employee()
{
    EmpID = "100",
    EmpName = "John",
    EmpMobile = new List<Mobile>()
    {
        new Mobile() { MobNumber = "55566610", IsPreferred = true, IsLive = false },
        new Mobile() { MobNumber = "55566611", IsPreferred = false, IsLive = true },
    },
    IsLive = true
},

new Employee()
{
    EmpID = "101",
    EmpName = "Peter",
    EmpMobile = new List<Mobile>()
    {
        new Mobile() { MobNumber = "55566610", IsPreferred = true, IsLive = false },
        new Mobile() { MobNumber = "55566611", IsPreferred = false, IsLive = false },
    },
    IsLive = true
},

new Employee()
{
    EmpID = "102",
    EmpName = "Jack",
    EmpMobile = new List<Mobile>()
    {
        new Mobile() { MobNumber = "55566610", IsPreferred = true, IsLive = true },
        new Mobile() { MobNumber = "55566611", IsPreferred = false, IsLive = true },
    },
    IsLive = false
}

}

collectionEmpInfo.InsertMany(EmpInfo);
var empList = collectionEmpInfo.Find(new BsonDocument()).ToList();

现在我希望Select只有EmpInfo.IsLive == true里面的嵌入文件我只需要EmpInfo.EmpMobile.IsLive == true 满意的移动文档

我的预期输出:

List<Employee> EmpInfo = new List<Employee>() {
new Employee()
{
    EmpID = "100",
    EmpName = "John",
    EmpMobile = new List<Mobile>()
    {
        new Mobile() { MobNumber = "55566611", IsPreferred = false, IsLive = true }
    },
    IsLive = true
},

new Employee()
{
    EmpID = "101",
    EmpName = "Peter",
    EmpMobile = new List<Mobile>()
    {

    },
    IsLive = true
}

}

请帮助我如何使用 c# MongoDB.[=19 为我的预期输出编写 Where 子句查询 =]

Note: Filter the Collection in DB instead of Memory

我的 MongoDB 库和连接是

IMongoClient _client = new MongoClient();
IMongoDatabase _database = _client.GetDatabase("Test");

我认为这可以解决您遇到的问题:

var collection = _database.GetCollection<Employee>("employee"); // (1)

var filterBuilder = Builders<BsonDocument>.Filter;
var filter = filterBuilder.Eq("IsLive", true) & filterBuilder.Eq("EmpMobile.IsLive", true); // (2)

var results = await collection.FindAsync(filter).ToListAsync(); // (3)

(1):您需要将集合名称更改为包含您要查询的数据的集合名称。另外,请注意它请求 TDocument 作为通用参数。似乎 Employee 没有继承自 TDocument,但您可以这样做,或者您可以为此目的创建另一个 DTO class。

(2):您可以使用位与运算符 (&) 组合条件。

此外,您可以直接查询数组的内部值(在您的 classes 中作为列表)。事实证明,如果任何数组值满足条件,它将 return 文档。在您的示例中,这应该 return EmpIDs 100 的文档,但它将包含两个 MobileNumbers。您检索到的是满足条件的文档,但您检索的是整个文档。

(3) 最后,将结果呈现到列表中,以便将它们保存在内存中。或者,您可以使用 cursor.MoveNextAsync() 遍历结果,但这将使您与 MongoDB 的连接打开时间更长。

您可以在 MongoDB 文档的 Find or Query Data with C# Driver 中找到大部分信息和示例。

您的方法有多个整数。

首先您使用的是 collectionEmpInfo.InsertOne(EmpInfo); 我假设您想改用 InsertMany

至于对集合进行过滤,您必须知道您的过滤器会影响是否检索到整个对象,因此在实体内的嵌入式数组上添加过滤器不会过滤数组,但会确定是否检索到整个对象根据是否匹配嵌入数组的查询条件来检索或不检索。我的建议是仅对查询中的员工应用筛选器并筛选内存中的结果集。

var filter = filterBuilder.Eq("IsLive", true);

var results = await collection.FindAsync(filter).ToListAsync();

现在像

一样过滤内存中的结果集合
var filteredResults = results.ForEach(employee => employee.EmpMobile = employee.EmpMobile.Where(mob => mob.isLive).ToList());

编辑

已添加 projection - 因此所选数组仅包含 IsLive==true

的文档

我认为使用类型查询更容易,因为 c# 是强类型语言。 我使用了 ElemMatch,因为它旨在扫描数组并查找匹配的元素。

var filterDef = new FilterDefinitionBuilder<Employee>();
var filter = filterDef.Eq(x => x.IsLive, true);

var projectDef = new ProjectionDefinitionBuilder<Employee>();
var projection = projectDef.ElemMatch<Mobile>("EmpMobile", "{IsLive:true}");            

var empList = collectionEmpInfo.Find(filter).Project<Employee>(projection).ToList();