Many of us would have already used MongoDB for storing data as Documents. However, I come from a world of SQL where everything is stored in Tables following the Normalization process. Hence, anything that can be further broken down, should be considered storing in a separate table.
In the world of MongoDB or rather, No-SQL, we do not have anything like that. Here, the more connected the data is supposed to have, the more chances of storing them together makes sense. Let’s look at the below example:
{ "_id":"d5ebb427", "name":"Anubhav Ranjan", "email":"[email protected]", "subscriptions":[ { "subscriptionId":"1abc", "showId":"d060b8ca", "notificationEnabled":true }, { "subscriptionId":"2abc", "showId":"d060b8cb", "notificationEnabled":true } ] }
Let’s consider the code snippet above. I have an object User having Two Subscriptions. Now I want to make one of the Subscriptions as false. This should be done using C#.
Let’s see how this can be achieved using Mongo shell
db.users.find({ _id: "d5ebb427", "subscriptions.subscriptionId":"1abc"}); db.users.update({ _id: "d5ebb427", "subscriptions.subscriptionId":"1abc"}, { $set: {"subscriptions.$.notificationEnabled": false}});
Let’s go ahead and check out the C# implementation
// C# Mongo Schema public class User { [BsonId] public string Id { get; set; } [BsonElement("name")] public string Name { get; set; } [BsonElement("email")] public string Email { get; set; } [BsonElement("subscriptions")] public Subscription[] Subscriptions { get; set; } } public class Subscription { [BsonElement("subscriptionId")] public string SubscriptionId{ get; set; } [BsonElement("showId")] public string ShowId { get; set; } [BsonElement("notificationEnabled")] public bool NotificationEnabled { get; set; } }
In order to do this, we are using the positional $ operator.
As per the MongoDB docs, The positional $
operator identifies an element in an array to update without explicitly specifying the position of the element in the array.
var filter = Builders.Filter; var userSubscriptionFilter = filter.And( filter.Eq(u => u.Id, id), filter.ElemMatch(u => u.Subscriptions, s => s.SubscriptionId == subId) ); // Find User with Id and Subscription Id var user = await usersCollection.Find(userSubscriptionFilter).SingleOrDefaultAsync(); // Update using the positional operator var update = Builders.Update; var subscriptinonSetter = update.Set("subscriptions.$.notificationEnabled", false); var updateResult = await usersCollection.UpdateOneAsync(userSubscriptionFilter, subscriptinonSetter);
After further reading, I have even found that you can change the line from this:
var subscriptinonSetter = update.Set("subscriptions.$.notificationEnabled", false);
to this:
var subscriptinonSetter = update.Set(s => s.Subscriptions[-1].NotificationEnabled, false);
Happy Coding!