Mongodb .Net Driver 2.0 Pull (Remove Element)

MongoDB .Net driver 2.0 Pull (remove element)

When using a filter to remove array elements, you need to use the PullFilter builder instead of Pull (which matches whole elements).

var collection = db.GetCollection<Person>("people");
var filter = new BsonDocument("username", "bodrum");
var update = Builders<Person>.Update.PullFilter("followerList",
Builders<Follower>.Filter.Eq("follower", "fethiye"));
var result = collection.FindOneAndUpdateAsync(filter, update).Result;

Or somewhat more succinctly, using lambdas:

var update = Builders<Person>.Update.PullFilter(p => p.followerList,
f => f.follower == "fethiye");
var result = collection
.FindOneAndUpdateAsync(p => p.username == "bodrum", update).Result;

MongoDB .Net Driver - Pull multiple elements from arrays that exist in multiple documents

Mongo .NET driver support scripting with untyped document (BsonDocument).

UpdateMany

Update many documents, equivalent to { multi: true }

You can achieve as below:

MongoClient _client = new MongoClient("mongo connection string");

IMongoDatabase _database = _client.GetDatabase("your DB");
IMongoCollection<Store> _collection = _database.GetCollection<Store>("store");

string[] removedFruits = new string[] { "apples", "bananas" };
FilterDefinition<Store> filter = Builders<Store>.Filter.Empty;

UpdateDefinition<Store> update =
new BsonDocument("$pull",
new BsonDocument("fruits",
new BsonDocument("$in", BsonArray.Create(removedFruits))
)
);

_collection.UpdateMany(filter, update);
public class Store
{
public string[] Fruits { get; set; }

// Other properties
}

How to remove a single Element from Array

In the Mongo Query Language the easiest way you can express this update is using the $[] (Positional All) operator. It looks something like this:

db.col.update({},{$unset:{"someArray.$[].IsReadOnly":1}},{multi:true})

However, this operator has not been explicitly implemented in the strongly typed Builders available in the C# Driver.

Since this operator is missing you have to build the update "by hand". Here's a quick sample.

var mongo = new MongoClient();
var db = mongo.GetDatabase("test");
var col = db.GetCollection<BsonDocument>("col");
await col.UpdateManyAsync(new BsonDocument(), Builders<BsonDocument>.Update.Unset("someArray.$[].IsReadOnly"));

There are some potential pitfalls here with field naming if you have some custom serialization settings (such as lower camel cased field names), so be sure to test things.

It is worth noting that this answer is contingent upon you running a version of MongoDB that is 3.6 or newer. If you are running an older version, this method will not work as the $[] operator does not exist in earlier versions.

C# MongoDB - How to add and remove item to multiple nested array elements?

You can try something like below in 2.5 driver with 3.6 version.

Finds the document with filter criteria and update which includes new positional identifier to update multiple elements in array inside UpdateOne method.

$[] updates all the Tags arrays to include new item in all Categories array. It acts as a placeholder for updating all elements in array.

Push

var filter = Builders<Product>.Filter.Eq("Id", "123");
var update = Builders<Product>.Update.Push("Tags.$[].Categories", "Item 3");
var result = collection.UpdateOne(filter, update);

Pull

var filter = Builders<Product>.Filter.Eq("Id", "123");
var update = Builders<Product>.Update.Pull("Tags.$[].Categories", "Item 3");
var result = collection.UpdateOne(filter, update);

Additional Information:

You can set the ArrayFilters options in UpdateOptions for applying query criteria on nested array to control what elements to update.

For example to update all the Categories in Tags array where each tag has Name name.

var filter = Builders<Product>.Filter.Eq("Id", "123");
var update = Builders<Product>.Update.Push("Tags.$[t].Categories", "Item 3");
var arrayFilters = new List<ArrayFilterDefinition>{ new ArrayFilterDefinition(new BsonDocument("t.Name", "name")) };
var updateOptions = new UpdateOptions({ArrayFilters = arrayFilters});
var result = collection.UpdateOne(filter, update, updateOptions);

MongoDB .NET Driver update Cannot use the part ... to traverse the element

$rename operator is not able to work in updating the field name in a nested array.

Instead, you need $set the existing Number value(s) to new field TestNumber with $map. Then $unset to remove Orders.TestNumber field.

Note: The previous answer will result in incorrect output. Need to use $map for updating the objects in array.

db.collection.update({},
[
{
$set: {
Orders: {
$map: {
input: "$Orders",
in: {
$mergeObjects: [
{
"Number-test": "$$this.Number"
},
"$$this"
]
}
}
}
}
},
{
$unset: "Orders.Number"
}
],
{
multi: true
})

Sample Mongo Playground


[For MongoDB .Net Driver version 2.13]

To C#, you need to use UpdateDefinitionBuilder<TDocument>.Pipeline Method as below:

Solution 1

UpdateDefinition<VisitTask> update = Builders<VisitTask>.Update.Pipeline(
new PipelineStagePipelineDefinition<VisitTask, VisitTask>(
new PipelineStageDefinition<VisitTask, VisitTask>[]
{
new BsonDocument("$set",
new BsonDocument("Orders",
new BsonDocument("$map",
new BsonDocument
{
{ "input", "$Orders" },
{ "in",
new BsonDocument("$mergeObjects",
new BsonArray
{
new BsonDocument("Number-test", "$$this.Number"),
"$$this"
})
}
}))),
new BsonDocument("$unset", "Orders.Number")
}));

Solution 2

UpdateDefinition<VisitTask> update = Builders<VisitTask>.Update.Pipeline(
new BsonDocument[]
{
new BsonDocument("$set",
new BsonDocument("Orders",
new BsonDocument("$map",
new BsonDocument
{
{ "input", "$Orders" },
{ "in",
new BsonDocument("$mergeObjects",
new BsonArray
{
new BsonDocument("Number-test", "$$this.Number"),
"$$this"
})
}
}))),
new BsonDocument("$unset", "Orders.Number")
}
);

Mongo update array element (.NET driver 2.0)

Took me a while to figure this out as it doesn't appear to be mentioned in any of the official documentation (or anywhere else). I did however find this on their issue tracker, which explains how to use the positional operator $ with the C# 2.0 driver.

This should do what you want:

public void UpdateItemTitle(string agendaId, string itemId, string title){
var filter = Builders<TempAgenda>.Filter.Where(x => x.AgendaId == agendaId && x.Items.Any(i => i.Id == itemId));
var update = Builders<TempAgenda>.Update.Set(x => x.Items[-1].Title, title);
var result = _collection.UpdateOneAsync(filter, update).Result;
}

Notice that your Item.Single() clause has been changed to Item.Any() and moved to the filter definition.

[-1] or .ElementAt(-1) is apparently treated specially (actually everything < 0) and will be replaced with the positional operator $.

The above will be translated to this query:

db.Agenda.update({ AgendaId: 1, Items.Id: 1 }, { $set: { Items.$.Title: "hello" } })

MongoDB .NET Driver - StartsWith & Contains with loosely typed data

If you cast to string instead of using AsString, it should work:

var results = query.Where(x => ((string) x["first_name"]).Contains("john")).Take(10);

Exception when deleting array element using PullFilter

Filters are typed and you must match up the filters to what they are filtering.

Your filter on the collection should be a FilterDefinition<Event>.

Your filter used with PullFilter should be a FilterDefinition<Document>.

This isn't caught at compile time because you used "DocId" to identify the field and so there is no type information associated with the field. The type of the field was inferred from the filter passed to PullFilter, which is a filter on Event.

I recommend using the typed versions of the Filter and Update builders. Here's your code rewritten using the typed versions which results in a compile time error:

var filter = Builders<Event>.Filter.Eq(x => x.EventId, "abc");
var update = Builders<Event>.Update.PullFilter(x => x.Documents, Builders<Event>.Filter.Eq(x => x.DocId, "abc"));
collection.FindOneAndUpdate(filter, update);

Here's the code using Document instead of Event in the last usage of Builders:

var filter = Builders<Event>.Filter.Eq(x => x.EventId, "abc");
var update = Builders<Event>.Update.PullFilter(x => x.Documents, Builders<Document>.Filter.Eq(x => x.DocId, "abc"));
collection.FindOneAndUpdate(filter, update);


Related Topics



Leave a reply



Submit