4

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.

1
  • Unwind the drivers, select only the active ones. Or do the same in code. Commented Jul 4, 2017 at 6:54

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the answer. Just tred it, but I get error: "Command find failed: Positional projection 'Drivers.$' does not match the query document.."
@user348173 Which form are you trying? Make sure you actually include part of the query to test for the IsActive is true. So if there is nothing trying to match an element of Drivers then you get that error.
I use the first form. Yes, I forgot to put Any. Anyway, now I get null result. But, in the database I see that one item has true
@user348173 It should not matter how many they are as the positional $ operator only returns the "first". Please do the query the second way for me whilst I check the LINQ syntax. Which is harder to check because I need to basically recreate your class structure.
@user348173 Included the logged query with MongoDB. It looks correct to me. Possibly your collection data does not match the class definitions
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.