MongoDB in C# - what is the right way to perform multiple filtering

Viewed 78

I have a MongoDB collection of Persons (person_Id, person_name, person_age)

I want to return an object that contains:

  1. number_of_all_persons
  2. number_of_all_persons with age < 20
  3. number_of_all_persons with age >= 20 && age <= 40
  4. number_of_all_persons with age > 40

What is the right way to do it in Mongo using C#?

Should I run 4 different Filters to achieve result?

2 Answers

You can use Aggregation.

const lowerRange = { $lt: ["$person_age", 20] };
const middleRange = { $and: [{ $gte: ["$person_age", 20]}, { $lte: ["$person_age", 40] }] };
// const upperRange = { $gt: ["$person_age", 40] };

db.range.aggregate([
    { 
        $project: {
            ageRange: { 
                $cond: { 
                    if: lowerRange, 
                    then: "lowerRange",
                    else: { 
                        $cond: {
                            if: middleRange, 
                            then: "middleRange", 
                            else: "upperRange"
                        }
                    }
                }
            }
        }
    }, 
    {
        $group: { 
            _id: "$ageRange",
            count: { $sum: 1 }
        }
    }
]);

Here the total count is not included as you can calculate it from the count of the ranges. If you have more that 3 ranges, a better idea would be to pass an array of $cond statements to the project stage, as nesting multiple if/else statements starts to get harder to maintain. Here is a sample:

$project: {    
    "ageRange": {
       $concat: [
          { $cond: [ { $lt: ["$person_age", 20] }, "0-19", ""] },
          { $cond: [ { $and: [ { $gte: ["$person_age", 20] }, { $lte: ["$person_age", 40] } ] }, "20-40", ""] },
          { $cond: [ { $gt: ["$person_age", 40] }, "41+", ""] }
       ]
    }  
} 

You have several possible solutions here.

  1. Filter with mongo
  2. Filter with Linq

Looks like you are having an "and" filter here. You can do your filtering as described here: Link to filtering

Or, depending on how large your persons collection is, you could do query for all objects and filter with linq:

var collection.FindAll().Where(x => (x.age < 20) && (x.age >= 20 && x.age <= 40) ...)

The above is not syntax correct but I hope you get the idea behind it.

My approach would be creating a filter builder and and adding it to the find method call.

var highExamScoreFilter = Builders<BsonDocument>.Filter.ElemMatch<BsonValue>(
    "scores", new BsonDocument { { "type", "exam" },
    { "score", new BsonDocument { { "$gte", 95 } } }
});
var highExamScores = collection.Find(highExamScoreFilter).ToList();

Hope this helps somehow.

Related