Hi Craig,
you are completely right that this isn't the answer I was looking for:
1. The answer that the professor79 gave me are great besides it does not solve my last question how to query a single element in an embedded array. A most basic operation in my opinion. It's quite easy to add/delete/update elements to a embedded array but not to query them again.You use $elemMatch in your projection. https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/. However, this doesn't work in the aggregation framework, which is why you use the $unwind stage.
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();
2. You did not answer my question related to the Wired Tiger engineI believe this is a relevant link: https://groups.google.com/forum/#!topic/mongodb-user/nV-DWbgB2oM. Long and short of it is that wired tiger does better with embedded arrays than mmapv1.
3. The solution that professor79 came up on SO are in no way what I would expect to have embedded arrays supported by c# drivers. I actually have to use native mongodb query syntax to achieve most basic CRUD operationsI don't understand your question. We've done our best to create a type-safe API to allow you to do almost everything that is possible with native syntax. Perhaps an example of something you can't do which is requiring you to fall back would be helpful.
//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"));
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)
.Unwind("children").Sort(sort).Limit(1).Project<Child>(project);
var result = aggregate.FirstOrDefault();
6. I would like to have all data of one user in one document so I have a clear idea how my design should be, but does it make sense if I add a record per day? And even if yes does it make sense if it's so complicated to access the nested data from c#?There are many ways to think about this. I understand that your user is your aggregate root and it would be nice to have all the data of that aggregate root in a single document. If the design feels right, then go for it. If it doesn't, then perhaps your aggregate root is wrong. However, it's not any more complicated to access nested data in C# than it is in other languages or the shell. It seems your complaint lies not with the driver, but with the general syntax. If I'm hearing this incorrectly, please point out places where we can improve. We are always happy to receive constructive feedback.
7. I ensure you I spend hours search the web for information on this topics but did not find satisfying answers because most posts use the old drivers and not V2This really shouldn't be a problem. I'm sorry there are less resources available. It's a new API and people haven't written about it as much. Here is the link to the documentation (which can always be improved): http://mongodb.github.io/mongo-csharp-driver/. However, the basic principles remain the same in whichever API your are using. Understand what you are trying to do in native MongoDB syntax, then translate that into C#.
Thanks for the explanation let me elaborate1. The answer that the professor79 gave me are great besides it does not solve my last question how to query a single element in an embedded array. A most basic operation in my opinion. It's quite easy to add/delete/update elements to a embedded array but not to query them again.You use $elemMatch in your projection. https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/. However, this doesn't work in the aggregation framework, which is why you use the $unwind stage.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();Still does not return an array of kids. What do I need to change here?
2. You did not answer my question related to the Wired Tiger engineI believe this is a relevant link: https://groups.google.com/forum/#!topic/mongodb-user/nV-DWbgB2oM. Long and short of it is that wired tiger does better with embedded arrays than mmapv1.In the online course it was said thate WiredTiger does not reserve space for extending documents but that if document are extended it will copy the whole document to a new location. Therefore I was wondering if it then is a good choice if I will add array elements.
3. The solution that professor79 came up on SO are in no way what I would expect to have embedded arrays supported by c# drivers. I actually have to use native mongodb query syntax to achieve most basic CRUD operationsI don't understand your question. We've done our best to create a type-safe API to allow you to do almost everything that is possible with native syntax. Perhaps an example of something you can't do which is requiring you to fall back would be helpful.Just compare://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"));which is pretty straight forward using the API because it is suported by the builders tovar 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)
.Unwind("children").Sort(sort).Limit(1).Project<Child>(project);
var result = aggregate.FirstOrDefault();To access the youngest child. I would expect to have an easier way to access and filter elements of embedded arrays
6. I would like to have all data of one user in one document so I have a clear idea how my design should be, but does it make sense if I add a record per day? And even if yes does it make sense if it's so complicated to access the nested data from c#?There are many ways to think about this. I understand that your user is your aggregate root and it would be nice to have all the data of that aggregate root in a single document. If the design feels right, then go for it. If it doesn't, then perhaps your aggregate root is wrong. However, it's not any more complicated to access nested data in C# than it is in other languages or the shell. It seems your complaint lies not with the driver, but with the general syntax. If I'm hearing this incorrectly, please point out places where we can improve. We are always happy to receive constructive feedback.Yes you got my intention. Ok it might then be a problem with the general syntax, but it would be great to if the c# driver would make it easier to work with arrays.
7. I ensure you I spend hours search the web for information on this topics but did not find satisfying answers because most posts use the old drivers and not V2This really shouldn't be a problem. I'm sorry there are less resources available. It's a new API and people haven't written about it as much. Here is the link to the documentation (which can always be improved): http://mongodb.github.io/mongo-csharp-driver/. However, the basic principles remain the same in whichever API your are using. Understand what you are trying to do in native MongoDB syntax, then translate that into C#.Yes, I've read your documentation at the link your provided. Unfortunately I did not find anything about the usage of arrays. Would be great if this could be added.
I really don't want to be a pain in your neck, I'm just trying to understand. As said before I have my app running now with seperate collections, but it would be nice if I can change that.BestThomas
var aggQuery = families.Aggregate() .Match(x => x.Id == 2) .Unwind<Family, UnwoundFamily>(x => x.Children) .Limit(1) .Project(x => new { x.Child }); //.Project(x => x.Child) wanted to do this, but seems like we have a bug
Console.WriteLine(aggQuery); Console.WriteLine();
foreach (var result in aggQuery.ToEnumerable()) { Console.WriteLine(result); }
var linqQuery = families.AsQueryable() .Where(x => x.Id == 2) .SelectMany(x => x.Children) .Take(1);
Console.WriteLine(linqQuery); Console.WriteLine();
foreach (var result in linqQuery) { Console.WriteLine(result); }