MongoDB updateOne - c#

I am trying to update an existing Mongo record, but am getting an "Additional information: Element name 'ID' is not valid'." error
I have a a BsonDocument "document" containing data that I retrieve from another source that looks like this:
{ "ID" : "ABCecdcf9851efbf0ef66953", ListingKey : "234534345345", "Created" : ISODate("2017-08-04T00:31:23.357Z"), "Modified" : ISODate("2017-08-04T00:31:23.358Z"), "Field1" : 1, "Field2" : "0.09", "Field3" : "1.10", "Field4" : "1", "Field5" : "1" }
Here is the C# code that I have written:
var collection = db.GetCollection<BsonDocument>("MyCollection");
//Hard coded for testing
var filter = Builders<BsonDocument>.Filter.Eq("ListingKey", "234534345345");
collection.UpdateOne(filter, document);
Is this related to the BsonDocument that I am trying to use to update? I found this documentation, which causes me to think that this is the cause. If so, is there a way to do an update with the format I have been provided?
https://docs.mongodb.com/getting-started/csharp/update/
I had a process working where it would delete the document and then add a new document, but for efficiency's sake I need this to update. Ideally it will only update the fields that are present in the BsonDocument and keep the existing fields in the Mongo document as is.

My problem was because I did not have the correct value when trying to update. My code works with this:
var collection = db.GetCollection<BsonDocument>("MyCollection");
//Hard coded for testing
var filter = Builders<BsonDocument>.Filter.Eq("ListingKey", "234534345345");
var update = Builders<BsonDocument>.Update.Set("Created", DateTime.UtcNow);
foreach (BsonElement item in document)
{
update = update.Set(item.Name, item.Value);
}
var result = collection.UpdateOne(filter, update);
I had to convert my string into an update BsonDocument.

Related

C# - MongoDB - Update an element inside a Nested Document

I have a MongoDB Document as follows
{
"_id" : ObjectId("5a55775cbd12982cc063c71a"),
"ShipmentNumber" : "00004000000048652254",
"Cartons" : [
{
"_id" : ObjectId("5a5575bcbd12982cc063b718"),
"CartonNumber" : "0076013926580S",
"Skus" : [
{
"_id" : ObjectId("5a5575bcbd12982cc063b719"),
"SkuNumber" : "06577647",
"ShippedQuantity" : 12,
},
{
"_id" : ObjectId("5a5575bcbd12982cc063b519"),
"SkuNumber" : "06577657",
"ShippedQuantity" : 15,
}
],
"IsScanned" : false,
},
}
How can I update the "ShippedQuantity" for a particular Sku element based on its "_id" in C# code ?
I tried something like below. But it is not working.
Getting error message like
cannot use the part (Cartons of Cartons.$[].Skus.$.ShippedQuantity) to
traverse the element
var filter = Builders<BsonDocument>.Filter.Eq("Cartons.Skus._id", new ObjectId("5a5575bcbd12982cc063b519"));
var update = Builders<BsonDocument>.Update.Set("Cartons.$[].Skus.$.ShippedQuantity", 50)
I am facing difficulties when I try to update multi level documents.
(In this case I have a list of Cartons and each carton will have its own list of skus and I need to update a specific sku's element)
Please provide a solution or alternative approach to update this inner level (more than 2 levels) documents in MongoDB using C#.
I updated my MongoDB server to the latest 3.6.1. But that is also not helping.
Thanks for your help.
First, you need to run this command in your MongoDB to apply the new features of version 3.6.1 db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )
Here is the code you need for that update:
var filter = Builders<YOUR_CLASS>.Filter.Eq("_id", new ObjectId("5a55775cbd12982cc063c71a"));
var update = Builders<YOUR_CLASS>.Update.Set("Cartons.$[i].Skus.$[j].ShippedQuantity", 50);
var arrayFilters = new List<ArrayFilterDefinition>
{
new BsonDocumentArrayFilterDefinition<Setup>(new BsonDocument("i._id", new ObjectId("5a5575bcbd12982cc063b718"))),
new BsonDocumentArrayFilterDefinition<Setup>(new BsonDocument("j._ID", new ObjectId("5a5575bcbd12982cc063b719")))
};
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
var (updated, errorMessage) = await UpdateOneAsync(filter, update, updateOptions);
Additionally, you can run set these settings in your MongoDB to look at your final queries and run them manually in RoboMongo or Studio 3T to debug them:
db.setProfilingLevel(2) -> to view query logs under C:\data\log\mongod.log
db.setLogLevel(5) -> to view query logs under C:\data\log\mongod.log
look for the "UPDATE" query in the log file. After that, you can reset the log setting back to 0
db.setProfilingLevel(0)
db.setLogLevel(0)
I've had the same problem and asked the same question Here
Have a look at it.

Execute complex mongo JSON query using C# mongo driver

I have following mongo shell query:
{'field':'FieldOne','value':'FieldOne','category':'categoryOne'} , { 'Color' : { '$elemMatch' : { 'Value' : 'Green' } }}
Is there any way to execute same query using C# mongo driver?. I have tried using below C# code, but only the first one is getting executed:
BsonDocument query = BsonDocument.Parse("{'field':'Overall','value':'Overall','category':'LoggedIncidents'} , { 'Priority' : { '$elemMatch' : { 'Value' : 'P1' } }}");
QueryDocument queryDoc = new QueryDocument(query);
var result = collection.Find(queryDoc).ToListAsync().Result;
The first item ({'field':'FieldOne','value':'FieldOne','category':'categoryOne'}) is being executed but not the second one ({ 'Color' : { '$elemMatch' : { 'Value' : 'Green' } }}).
You are using it in find command if i'm not wrong.
the first "{}" is what the filter condition for find is. next set of parameters are essentially to show/hide the fields you need.
so if you want to filter by value of array "green" you can do this.
db.objects.find({"color":{$elemMatch:{value:"green"}}})
should give you the results you are looking for. but if you want to specifically show/hide fields, you can do
db.objects.find({"color":{$elemMatch:{value:"green"}}},{"field":1})
is this what you want to attain?

MongoDB/C# Update Collection entries

Hello I have a mongoDB Collection called Nodes whose structure is as follows:
{
"_id" : new BinData(3, "Ljot2wCBskWG9VobsLA0zQ=="),
"logicalname" : "Test Node",
"host" : "eh5tmb054pc",
"port" : 104,
"appendtimestamp" : false,
"studies" : ["1.3.12.2.1107"],
"tests" : [],
"mainentries" : [{
"_id" : "1.3.12.2.1107",
"Index" : 0,
"Type" : "Study"
}]
}
I created a new key called "mainentries" which is now storing the "studies" and "tests". So in order to support my new versions without hassle, I now want to write a method in my Setup Helper, which would enable me to read this collection - Check if studies,tests exists , If yes add the key "mainentries" and remove the studies/tests key.
My question is: What kind of query must I use to reach each collection of Nodes to check for the fields and update. I am using the MongoDB-CSharp community driver.
Would appreciate any help and pointers.
You can simply check whether the field(s) still exist(s):
var collection = db.GetCollection<Node>("nodes");
var nodes = collection.Find(Query.And( // might want Query.Or instead?
Query<Node>.Exists(p => p.Tests),
Query<Node>.Exists(p => p.Studies)).SetSnapshot();
foreach(var node in nodes) {
// maybe you want to move the Tests and Studies to MainEntries here?
node.MainEntries = new List<MainEntries>();
node.Test = null;
node.Studies = null;
collection.Update(node);
}
If you don't want to migrate the data, but just remove the fields and create new ones, you can also do in a simple batch update using $exists, $set and $remove

MongoDB: update only specific fields

I am trying to update a row in a (typed) MongoDB collection with the C# driver. When handling data of that particular collection of type MongoCollection<User>, I tend to avoid retrieving sensitive data from the collection (salt, password hash, etc.)
Now I am trying to update a User instance. However, I never actually retrieved sensitive data in the first place, so I guess this data would be default(byte[]) in the retrieved model instance (as far as I can tell) before I apply modifications and submit the new data to the collection.
Maybe I am overseeing something trivial in the MongoDB C# driver how I can use MongoCollection<T>.Save(T item) without updating specific properties such as User.PasswordHash or User.PasswordSalt? Should I retrieve the full record first, update "safe" properties there, and write it back? Or is there a fancy option to exclude certain fields from the update?
Thanks in advance
Save(someValue) is for the case where you want the resulting record to be or become the full object (someValue) you passed in.
You can use
var query = Query.EQ("_id","123");
var sortBy = SortBy.Null;
var update = Update.Inc("LoginCount",1).Set("LastLogin",DateTime.UtcNow); // some update, you can chain a series of update commands here
MongoCollection<User>.FindAndModify(query,sortby,update);
method.
Using FindAndModify you can specify exactly which fields in an existing record to change and leave the rest alone.
You can see an example here.
The only thing you need from the existing record would be its _id, the 2 secret fields need not be loaded or ever mapped back into your POCO object.
It´s possible to add more criterias in the Where-statement. Like this:
var db = ReferenceTreeDb.Database;
var packageCol = db.GetCollection<Package>("dotnetpackage");
var filter = Builders<Package>.Filter.Where(_ => _.packageName == packageItem.PackageName.ToLower() && _.isLatestVersion);
var update = Builders<Package>.Update.Set(_ => _.isLatestVersion, false);
var options = new FindOneAndUpdateOptions<Package>();
packageCol.FindOneAndUpdate(filter, update, options);
Had the same problem and since I wanted to have 1 generic method for all types and didn't want to create my own implementation using Reflection, I end up with the following generic solution (simplified to show all in one method):
Task<bool> Update(string Id, T item)
{
var serializerSettings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
var bson = new BsonDocument() { { "$set", BsonDocument.Parse(JsonConvert.SerializeObject(item, serializerSettings)) } };
await database.GetCollection<T>(collectionName).UpdateOneAsync(Builders<T>.Filter.Eq("Id", Id), bson);
}
Notes:
Make sure all fields that must not update are set to default value.
If you need to set field to default value, you need to either use DefaultValueHandling.Include, or write custom method for that update
When performance matters, write custom update methods using Builders<T>.Update
P.S.: It's obviously should have been implemented by MongoDB .Net Driver, however I couldn't find it anywhere in the docs, maybe I just looked the wrong way.
Well there are many ways to updated value in mongodb.
Below is one of the simplest way I choose to update a field value in mongodb collection.
public string UpdateData()
{
string data = string.Empty;
string param= "{$set: { name:'Developerrr New' } }";
string filter= "{ 'name' : 'Developerrr '}";
try
{
//******get connections values from web.config file*****
var connectionString = ConfigurationManager.AppSettings["connectionString"];
var databseName = ConfigurationManager.AppSettings["database"];
var tableName = ConfigurationManager.AppSettings["table"];
//******Connect to mongodb**********
var client = new MongoClient(connectionString);
var dataBases = client.GetDatabase(databseName);
var dataCollection = dataBases.GetCollection<BsonDocument>(tableName);
//****** convert filter and updating value to BsonDocument*******
BsonDocument filterDoc = BsonDocument.Parse(filter);
BsonDocument document = BsonDocument.Parse(param);
//********Update value using UpdateOne method*****
dataCollection.UpdateOne(filterDoc, document);
data = "Success";
}
catch (Exception err)
{
data = "Failed - " + err;
}
return data;
}
Hoping this will help you :)

Update field from c# driver

I have a document collection like this:
{
"_id" : ObjectId("4fb21439f31dfd122ce39c4a"),
"Name" : "Freelander 2",
"Manufacture" : "Landrover"
}
I am using the C# driver, and want to check whether the "Name" field exists; if it does not, I need to update it from the code. Can someone help on this? Please share sample code because I am a newbie to mongoDB.
You can use the exists operator:
db.myCollection.find( { Name: { $exists: true } } );
Using the C# driver, the equivalent would be something like this:
IMongoQuery query = Query.Exists("Name", true)
var results = myCollection.Find(query);
To set a value if it doesn't exist, you can use an Update statement like this:
IMongoQuery query = Query.Exists("name", true);
IMongoUpdate update = Update.Set("Name", "newvalue");
myCollection.Update(query, update);
I'm assuming you want to update all documents that don't have a Name field to the same value. You can do that in the mongo shell like this:
> db.test.update({Name:{$exists:false}}, {$set:{Name:"xyz"}}, false, true)
You can do the same thing in C# like this:
var query = Query.Exists("Name", false);
var update = Update.Set("Name", "xyz");
collection.Update(query, update, UpdateFlags.Multi);

Categories