Gunnar
Gunnar

Reputation: 986

.NET using MongoDB select based on list of subdocuments

I have a customers database, containing a list of the customers ip address ranges, to give them access to a system.

public class Customer
{
    [BsonId]
    public ObjectId Id { get; set; }
    public string Name { get; set; }
    public List<IPRange> IPRanges { get; set; }
}

public class IPRange
{
    public int Lower { get; set; }
    public int Upper { get; set; }
}

The ip's are converted in to integers, so it is easier (or at least i think it is) to compare them with an incoming ip address.

So the document in MongoDB looks something like this

{
    "_id": ObjectID("55f9ab5ac95fb323d8b724a8"),
    "Name": "Customername",
    "IPRanges": [
        {
            "Lower": 134743044,
            "Upper": 134744072
        }, 
        {
            "Lower": 3494108380,
            "Upper": 3494108894
        }
    ],
}

So the question is, how to compare an incoming IP with a customer, based on the array of ipranges? If that is not possible, how to do this in a better way?

I have tried a lot of combinations, non of them which work. I have managed to get it work, if the upper and the lower ip's are identical.

This is the closes I got to a solution

    private async static Task<bool> check(string ip = "")
    {
        db = Connect();

        var intIp = IPCalculator.IPToInt(ip); //converts the ip from string form e.g. "8.8.8.8" to integer

        var lowerFilter = Builders<IPRange>.Filter.Gte("Lower", intIp);
        var upperFilter = Builders<IPRange>.Filter.Lte("Upper", intIp);

        List<FilterDefinition<IPRange>> filters = new List<FilterDefinition<IPRange>>();
        filters.Add(lowerFilter);
        filters.Add(upperFilter);

        var customerFilter = Builders<Customer>.Filter.ElemMatch<IPRange>(ca => ca.IPRanges, Builders<IPRange>.Filter.And(filters));


        var customerCollection = db.GetCollection<Customer>("Customer").Find(customerFilter);

        var customerList = await customerCollection.ToListAsync();

        if (customerList.Count > 0)
        {
            return true;
        }
        return false;
    }

Upvotes: 2

Views: 45

Answers (1)

Evk
Evk

Reputation: 101493

It seems you just messed up a little here:

var lowerFilter = Builders<IPRange>.Filter.Gte("Lower", intIp);
var upperFilter = Builders<IPRange>.Filter.Lte("Upper", intIp);

because that would mean Lower >= ip and Upper <= ip. You need:

var lowerFilter = Builders<IPRange>.Filter.Lte("Lower", intIp);
var upperFilter = Builders<IPRange>.Filter.Gte("Upper", intIp);

Upvotes: 1

Related Questions