topolm
topolm

Reputation: 435

MongoDb c# driver consecutive SelectMany

If I have objects, lets call them Group that has list of some other objects I will call it Brand, and this object has a list of objects called Model.

Is there a way to get only list of Models using MongoDb c# driver.

I tried using SelectMany multiple times but with no success. If I put more than one SelectMany I always get an empty list.

Code should be self-explanatory. At the end is comment that explains what confuses me.

class Group
{
    [BsonId(IdGenerator = typeof(GuidGenerator))]
    public Guid ID { get; set; }
    public string Name { get; set; }
    public List<Brand> Brands { get; set; }
}

class Brand
{
    public string Name { get; set; }
    public List<Model> Models { get; set; }
}

class Model
{
    public string Name { get; set; }
    public int Produced { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        MongoClient client = new MongoClient("mongodb://127.0.0.1:32768");
        var db = client.GetDatabase("test");
        var collection = db.GetCollection<Group>("groups");

        var fca = new Group { Name = "FCA" };

        var alfaRomeo = new Brand { Name = "Alfra Romeo" };
        var jeep = new Brand { Name = "Jeep" };
        var ferrari = new Brand { Name = "Ferrari"};

        var laFerrari = new Model { Name = "LaFerrari", Produced = 4 };

        var wrangler = new Model { Name = "Wrangler", Produced = 3 };
        var compass = new Model { Name = "Compass", Produced = 8 };

        var giulietta = new Model { Name = "Giulietta", Produced = 7 };
        var giulia = new Model { Name = "Giulia", Produced = 8 };
        var _4c = new Model { Name = "4C", Produced = 6 };        

        fca.Brands = new List<Brand> { ferrari, alfaRomeo, jeep };

        ferrari.Models = new List<Model> { laFerrari };
        jeep.Models = new List<Model> { wrangler, compass };
        alfaRomeo.Models = new List<Model> { giulietta, giulia, _4c };

        collection.InsertOne(fca);                 

        Console.WriteLine("press enter to continue");
        Console.ReadLine();

        var models = collection.AsQueryable().SelectMany(g => g.Brands).SelectMany(b => b.Models).ToList();
        Console.WriteLine(models.Count);    //returns 0 I expected 6
        Console.ReadLine();

    }
}

Upvotes: 1

Views: 3938

Answers (1)

Mate
Mate

Reputation: 5274

Try

var models = collection.AsQueryable()
 .SelectMany(g => g.Brands)
 .Select(y => y.Models)
 .SelectMany(x=> x);

Console.WriteLine(models.Count());

Working output (with extra Select())

aggregate([{
    "$unwind": "$Brands"
}, {
    "$project": {
        "Brands": "$Brands",
        "_id": 0
    }
}, {
    "$project": {
        "Models": "$Brands.Models",
        "_id": 0
    }
}, {
    "$unwind": "$Models"
}, {
    "$project": {
        "Models": "$Models",
        "_id": 0
    }
}])

OP Output without extra Select()

 aggregate([{
    "$unwind": "$Brands"
}, {
    "$project": {
        "Brands": "$Brands",
        "_id": 0
    }
}, {
    "$unwind": "$Models"
}, {
    "$project": {
        "Models": "$Models",
        "_id": 0
    }
}])

Upvotes: 5

Related Questions