Home > Software engineering >  Filtering a collection against a list of combinations in mongodb
Filtering a collection against a list of combinations in mongodb

Time:09-27

We have a collection of users with the following class definition.

public class User
{
    public Guid UserId { get;set; }
    public Guid CompanyId { get;set; }
    public Guid AddressTypeId { get;set; }
    public Guid LocationId { get;set; }
    public Guid DepartmentId { get;set; }
}

We're trying to query a list of users with a companyId, that matches a list of LocationFilter, with the following class definition.

public class LocationFilter
{
    public Guid AddressTypeId { get;set; }
    public ICollection<Guid> LocationIds { get;set; }
    public ICollection<Guid> DepartmentIds { get;set; }
}

The querying API definition will look like this:

Task<List<User>> GetUserLocationList(
  Guid companyId, 
  List<LocationFilter> locationFilters);

I have the following Builder queries if we're querying against a single LocationFilter.

var companyIdFilter = Builders<User>.Filter
  .Eq(user => user.CompanyId, companyId);
var addressTypeIdFilter = Builders<User>.Filter
  .Eq(user => user.AddressTypeId, addressTypeId);
var locationIdFilter = Builders<User>.Filter
  .In(user => user.LocationId, locationIds);
var departmentIdFilter = Builders<User>.Filter
  .In(user => user.DepartmentId, departmentIds);

var andFilter = Builders<User>.Filter
  .And(
    companyIdFilter, 
    addressTypeIdFilter,
    locationIdFilter,
    departmentIdFilter);

var result = await collection.Find(andFilter).ToListAsync();

But how do we filter against a list of locationfilter? Each locationfilter is it's own, it cannot intersect. For example, all users checked against location filter A, then against location filter B etc.

How can we achieve that using builder queries? Is this the right approach?

CodePudding user response:

You can use an Or to combine the location filters to find any users that matches (at least) one of the filters, e.g. (assuming that all users should be from the same company):

public FilterDefinition<User> BuildLocationFilter(LocationFilter locFilter)
{
    var addressTypeIdFilter = Builders<User>.Filter
      .Eq(user => user.AddressTypeId, locFilter.AddressTypeId);
    var locationIdFilter = Builders<User>.Filter
      .In(user => user.LocationId, locFilter.LocationIds);
    var departmentIdFilter = Builders<User>.Filter
      .In(user => user.DepartmentId, locFilter.DepartmentIds);
    
    var andFilter = Builders<User>.Filter
      .And(
        companyIdFilter, 
        addressTypeIdFilter,
        locationIdFilter,
        departmentIdFilter);

    return andFilter;
}

public FilterDefinition<User> BuildCompanyAndLocationFilters(
    Guid companyId, 
    IEnumerable<LocationFilter> locFilters)
{
    var locFilterDefs = 
        Builders<User>.Filter.Or(locFilters.Select(x => BuildLocationFilter(x)));
    return Builders<User>.Filter.Eq(x => CompanyId, companyId)
        & locFilterDefs;  
}

This retrieves all the users of the company that fulfill at least one company filter condition.

  • Related