Reputation: 9288
I have the following model:
public class Car
{
public string Id {get; set;}
public IList<Driver> Drivers {get; set;}
}
public Driver
{
public string Id {get; set;}
public bool IsActive {get; set;}
}
How can I select driver that is active?
var carId = "...";
var activeDriver = await _carCollection.Find(a => a.Id == carId
&& a.Drivers.Any(e=>e.IsActive))
.Project(a=>a.Drivers)
.SingleOrDefaultAsync();
This code returns IList<Driver>
, so all items. But I want to retrieve only one Driver
that is active.
Upvotes: 4
Views: 4569
Reputation: 305
The above accepted answer did not work for me. It returned nothing. You can use the following code:
var activeDriver = await _carCollection.AsQueryable().Where(a => a.Id == carId).SelectMany(a => a.Drivers).Where(e => e.IsActive).FirstOrDefault();
You can check this link
Upvotes: 0
Reputation: 151220
You basically need to include the positional $
operator in order to just return the matched array element from the query conditions given. You can do this with ElementAt(-1)
var activeDriver = await _carCollection.Find(a => a.Id == carId
&& a.Drivers.Any(e => e.IsActive))
.Project(a => a.Drivers.ElementAt(-1))
.SingleOrDefaultAsync();
And can also be written as:
var builder = Builders<BsonDocument>.Filter;
var activeDriver = await _carCollection.Find(
builder.Eq("Id", carId) & builder.Eq("Drivers.IsActive", true))
.Project(Builders<BsonDocument>.Projection.Include("Drivers.$"))
.SingleOrDefaultAsync();
If I run either of those then I get the serialized output of what get's sent to MongoDB as:
{
"find" : "cars",
"filter" : { "_id" : "a", "Drivers" : { "$elemMatch" : { "IsActive" : true } } },
"projection" : { "Drivers.$" : 1, "_id" : 0 },
"limit" : 2,
"$db" : "test"
}
Which matches exactly what the query should be.
Upvotes: 5