Reputation: 2172
I am using the official C# MongoDb strongly typed driver version 2.7.0-beta001 to interact with MongoDB v 4.0-rc1 on Windows 10 machine.
Consider the following classes:
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; }
}
How to update a library document if all author books are verified, here is my code:
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);
The last line throws System.ArgumentException: Unsupported filter: All
Upvotes: 3
Views: 5146
Reputation: 49945
In your POCO class Books
is a .NET List so you can (theoretically) use all extension methods (like All
). The problem is that it's not LINQ to objects so this expression is not evaluated in memory. MongoDB driver is trying to convert this into MongoDB query and as you can see there's no corresponding operator in MongoDB query language.
What you can do ? You can try to rewrite this filter into something else (keeping the same logical meaning). For instance you can use $elemMatch. Instead of trying to find all books with IsVerified
equal to true, you can build your query trying to find documents having at least one book equal to false and then use $not
to negate that condition. In that case $elemMatch
becames helpful:
The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
So not on at least one means none.
Then your code can look like this:
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);
Upvotes: 4