如何在C#Mongodb强类型驱动程序中基于嵌套数组元素进行过滤

时间:2018-06-06 18:48:36

标签: c# .net mongodb mongodb-query mongodb-.net-driver

我正在使用官方C#MongoDb强类型驱动程序版本2.7.0-beta001与Windows 10计算机上的MongoDB v 4.0-rc1进行交互。

考虑以下课程:

public class Library
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public DateTime DateAdded { get; set; }

    public DateTime LastModified { get; set; }

    public string Title { get; set; }

    public Author Author { get; set; }

    public bool AllBooks { get; set; }
}

public class Author {
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string BirthDate { get; set; }

    public string ScientificDegree { get; set; }

    public List<Book> Books { get; set; }
}

public class Book
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public string Title { get; set; }

    public int PublishYear { get; set; }

    public string Content { get; set; }

    public bool IsVerified { get; set; }
}

如果所有作者书籍都经过验证,如何更新库文档,这是我的代码:

string libraryId = GetLibraryId();

var repository = _database.GetCollection<Library>("Libraries");

var filter = Builders<Library>.Filter.Where(l => l.Id == libraryId &&
                l.Author.Books.All(b => b.IsVerified == true));

var update = Builders<Library>.Update.Set(l => l.AllBooks, true);

await repository.UpdateOneAsync(filter, update);

最后一行抛出System.ArgumentException:Unsupported filter:All

1 个答案:

答案 0 :(得分:1)

在您的POCO类中,Books是一个.NET列表,因此您可以(理论上)使用所有扩展方法(如All)。问题是它不是对象的LINQ,所以这个表达式不在内存中计算。 MongoDB驱动程序正在尝试将其转换为MongoDB查询,因为您可以看到MongoDB查询语言中没有相应的运算符。

你能做什么?您可以尝试将此过滤器重写为其他内容(保持相同的逻辑含义)。例如,您可以使用$elemMatch。您可以构建查询,尝试查找至少有一本等于false的图书的文档,然后使用IsVerified来否定该条件,而不是尝试查找$not等于true的所有图书。在这种情况下,$elemMatch有用:

  

$ elemMatch运算符将包含数组字段的文档与至少一个元素匹配,该元素与所有指定的查询条件匹配。

至少一个 意味着

然后你的代码看起来像这样:

var col = mydb.GetCollection<Library>("Libraries");
var filter = Builders<Library>.Filter.Not(
    Builders<Library>.Filter.ElemMatch(x => x.Author.Books, b => b.IsVerified == false));

var update = Builders<Library>.Update.Set(l => l.AllBooks, true);

await col.UpdateManyAsync(filter, update);