The $push operator is used to append a new item to an array. To push a new item create an UpdateDefinition<T> by defining the array field and the new item to push.
To push multiple items in a array field use the UpdateDefinitionBuilder<T>.PushEach method. The method creates a $push => $each operation and pushes all array items to the array field.
PushEach method accepts an optional parameter slice which when set properly can provide a queue functionality. Assume there's a SocialAccount document containing an array of notifications but you wish to always contain the last 2 inserted.
The sample tries to add 4 new notifications in the lastNotifications array field using a $slice:-2 operation. The resulting document contains only the last 2 notifications added.
var newNotifications =newList<Notification>();for (int i =0; i <4; i++){newNotifications.Add(newNotification() { Link =$"link-{i}", Text =$"text-{i}" });}var pushNotificationsDefinition =Builders<SocialAccount>.Update .PushEach(a =>a.LastNotifications, newNotifications, slice:-2); // $slice:-2var pushNotificationsResult =await socialNetworkCollection .UpdateOneAsync(Builders<SocialAccount> .Filter.Eq(a =>a.Id,firstAccount.Id), pushNotificationsDefinition);firstAccount =await socialNetworkCollection .Find(Builders<SocialAccount>.Filter.Empty) .FirstOrDefaultAsync();
db.social_network.updateOne( {}, { $push: { lastNotifications: { $each: [ { // this will be discard text:'text-0', link:'link-0' }, { // this will be discard text:'text-1', link:'link-1' }, { text:'text-2', link:'link-2' }, { text:'text-3', link:'link-3' } ], $slice:-2 } } });
The sample removes two string values ("FIFA 20", "NBA 2K17") from the PcGames string array field. The empty filter ensures to remove the items for all documents in the collection.
UpdatingArrays.cs
var storesCollection = database .GetCollection<StoreItem>(Constants.StoreCollection);var storeEmptyFilter =Builders<StoreItem>.Filter.Empty;// items to be removedvar removePcGames =newList<string> { "FIFA 20","NBA 2K17" };// create the definitionvar pullPcGamesDefinition = Builders<StoreItem> .Update.PullFilter(s =>s.PcGames, game =>removePcGames.Contains(game));var simplePullResult =await storesCollection .UpdateManyAsync(storeEmptyFilter, pullPcGamesDefinition);
To remove nested documents from an array field create an UpdateDefinition with the specified condition to be applied on the documents to be removed. Assuming T is the type of the root document which contains an array field having E type of documents, the syntax is the following.
var pullDefinition =Builders<T>.Update .PullFilter(root => root.<array-field>, arrayDoc => condition(arrayDoc<field>));
The sample removes VisitedCountry documents from the VisitedCountries array field of Traveler documents based on the VisitedCountry.TimesVisited value.
UpdatingArrays.cs
var travelersCollection = database .GetCollection<Traveler>(Constants.TravelersCollection);// create a filtervar visited8Times = Builders<Traveler> .Filter.ElemMatch(t =>t.VisitedCountries, country =>country.TimesVisited==8);var pullVisited8TimesDefinition =Builders<Traveler>.Update .PullFilter(t =>t.VisitedCountries, country =>country.TimesVisited==8); // conditionvar visited8TimesResult =await travelersCollection .UpdateManyAsync(visited8Times, pullVisited8TimesDefinition);
To update a specific array element without knowing its position in the array, you can use the $ positional operator. The driver can build such a query by translating the array[-1] as a positional operator.
The sample sets the Name value for all matched array VisitedCountry elements having Name = Greece and TimesVisited = 3.
UpdatingArrays.cs
var travelersCollection = database .GetCollection<Traveler>(Constants.TravelersCollection);// create an elemMatch operatorvar visitedGreeceExactly3Times =Builders<Traveler>.Filter .ElemMatch(t =>t.VisitedCountries, country =>country.Name=="Greece"&&country.TimesVisited==3);// create the update definitionvar updateDefinition =Builders<Traveler>.Update .Set(t =>t.VisitedCountries[-1].Name,"Hellas");// this will update only the first matching array element! // ($) refers to the first matchvar updateHellasResult =await travelersCollection .UpdateManyAsync(visitedGreeceExactly3Times, updateDefinition);
Normally, based on the $elemMatch operator, the $set operator should have been applied to the root document(s) but the $ position operator causes the update to be applied on the matched document instead
Update multiple elements
To update multiple array elements that match a specified condition, you need to use one or more ArrayFilterDefinition filters as the 3rd argument in the UpdateOne or UpdateMany methods.
Assume that you have a post which contains a list of comments.
The filter definition - in the sample it's a specific post matched by its _id but it could be anything
The update definition - the sample defines that the matched elements in the comments array field should set their hidden value to true. This is defined using the $positional operator and the elem identifier for each matching document
The ArrayFilters which defines how elem array elements are matched, in other words, which are the elements to be updated
Unfortunately, you cannot write this kind of operation using the typed way yet, because it's currently not supported by the driver . Of course, as soon as a new version that provides this functionality is released, the docs will be updated accordingly