2

I'm totally lost on doing CRUD and other operations on array elements in an embedded Array in mongodb using c# drivers.

given I have the following classes (simple example):

public class Child
{
    public ObjectId Id;
    public DateTime dateOfBirth;
    public string givenName;
}


class Family
{
    public ObjectId Id;
    public string name;
    public List<Child> children;
}

My collection should store Family documents.

How do I:

  1. Add a new child to a Family
  2. Delete a certain child
  3. Update one Child
  4. Count the children of one family
  5. get the youngest child of a family
  6. Load one specific Child

WITHOUT loading the whole Family object

Although I'm taking part in a mongo university class mongo.net I'm completely lost and the documentation on working with arrays is almost not existing.

I know got answers for 1-4:

    //Add child
    families.UpdateOne(Builders<Family>.Filter.Where(x=>x.name=="Burkhart"), Builders<Family>.Update.AddToSet("children",
        new Child() {dateOfBirth = new DateTime(2005, 4, 26), givenName = "Finn"}));

    // Add another
    families.UpdateOne(Builders<Family>.Filter.Where(x => x.name == "Burkhart"), Builders<Family>.Update.AddToSet("children",
        new Child() { dateOfBirth = new DateTime(2007, 4, 26), givenName = "Florentina" }));

    //remove one
    families.UpdateOne(Builders<Family>.Filter.Where(x => x.name == "Burkhart"),
        Builders<Family>.Update.PullFilter(c => c.children, m => m.givenName == "Florentina"));

    //update one
    families.UpdateOne(Builders<Family>.Filter.Where(x => x.name == "Burkhart" && x.children.Any(c => c.givenName =="Finn")), 
                       Builders<Family>.Update.Set(x=> x.children[-1].givenName,"Finn Linus"));

    //count children
    var numberOfChildren =
        families.Aggregate()
            .Match(f => f.name == "Burkhart")
            .Project(new BsonDocument("count", new BsonDocument("$size", "$children")))
            .FirstOrDefault()
            .GetValue("count")
            .ToInt32();
Thomas
  • 8,397
  • 7
  • 29
  • 39
  • you can download mongo driver from github and see tests -> examples – profesor79 Jun 14 '16 at 20:12
  • I did that but there are no examples for my questions – Thomas Jun 15 '16 at 09:47
  • that's strange ` [Fact] public void AddToSetEach_Typed() { var subject = CreateSubject(); Assert(subject.AddToSetEach(x => x.FavoriteColors, new[] { "green", "violet" }), "{$addToSet: {colors: {$each: ['green', 'violet']}}}"); Assert(subject.AddToSetEach("FavoriteColors", new[] { "green", "violet" }), "{$addToSet: {colors: {$each: ['green', 'violet']}}}"); }` – profesor79 Jun 15 '16 at 09:58
  • from `UpdateDefinitionBuilderTests` – profesor79 Jun 15 '16 at 09:59
  • But that ueses string type filters and also does an update each not a single one. I found a solution for Update now I add it above – Thomas Jun 15 '16 at 10:14
  • perfect :-) for 6 you will go with `ProjectionDefinitionBuilderTests` to use elemMatch, and 5 needs aggregation `AggregateFluentTests` – profesor79 Jun 15 '16 at 10:55
  • But with elemMatch I get the whole familiy object that contains a child that matches the value given elementMatch. I want only the Child object – Thomas Jun 15 '16 at 11:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/114743/discussion-between-thomas-and-profesor79). – Thomas Jun 15 '16 at 11:36

1 Answers1

3

as 1-4 was fixed by you - congratulations! Please find 5 and 6 as discussed in chat.

Full code in this GitHub repository

        var f = GenerateFaimly();
        collection.InsertOne(f);

        var sort = BsonDocument.Parse("{\"kids.dateOfBirth\": -1}"); // get the youngest 
        var project =
            BsonDocument.Parse(
                "{_id:'$children._id', dateOfBirth:'$children.dateOfBirth', givenName:'$children.givenName', IsAlive:'$children.IsAlive'}");
        var aggregate = collection.Aggregate().Match(x => x.Id == f.Id)

            // .Project(x => new { kids = x.children })
            .Unwind("children").Sort(sort).Limit(1).Project<Child>(project);

        Console.WriteLine(aggregate.ToString());

        var result = aggregate.FirstOrDefault();

        var pojectionIsAlive =
            BsonDocument.Parse(
                "{_id:1, name:1, children:{$filter:{ input:'$children', as:'kids', cond:{$eq:['$$kids.IsAlive', true]}}}}");

        var kids = collection.Aggregate().Match(x => x.Id == f.Id).Project<Family>(pojectionIsAlive).ToList();
profesor79
  • 9,213
  • 3
  • 31
  • 52
  • I just tried it again, and both don't work yet. Looking for the youngest does not return Child 4 as expected but Child 1 And selecting a single child does not work either :-( – Thomas Jul 04 '16 at 14:29
  • that's strange - did the test again and have child no 4 :( – profesor79 Jul 04 '16 at 15:31
  • Just uploaded a screenshot to the chat. I'm still surpised, that the above code runs at your side, at mine I get an exception when the RegisterClassMap is not placed to the very beginning. – Thomas Jul 04 '16 at 19:45
  • Hmm, as far as I remember we decided to put this class on the top of all methods. Will edit that tomorrow morning. – profesor79 Jul 04 '16 at 22:19
  • I just checked the GitHub Code, but still the projectionsIsAlive does not work. It returns a familiy Object with three Kids instead an List of Kids. – Thomas Jul 11 '16 at 12:26
  • Have a look ate the conversation with Craig Wilson https://groups.google.com/forum/#!topic/mongodb-csharp/YbyY8n2lbYk It can be done very elegant using Linq – Thomas Jul 15 '16 at 16:35
  • Hey guys, this question and answer is helping me but I need help on a different problem, Using this example, I need to count Child where givenName is "something". Can you help me here or at https://stackoverflow.com/questions/58572968/how-to-count-select-and-update-nested-elements-in-mongodb-c-sharp#comment103462808_58572968, please? – programad Oct 26 '19 at 18:23