How to update a nested document in a mongodb with c# - c#

I hope someone can help me to understand how I can update a document in a mongodb.
My problem is that i have a document which contains an array. And in this array there are objects with a specific ID(like you would find in sql database). Now I want to update the data inside those objects if they have the searched id.
A document looks like this
{
"_id": "63dafa72f21d48312d8ca405",
"tasks": [{
"_ref": "63d8d8d01beb0b606314e322",
"data": {
"values": [{
"key": "Deadline",
"value": "2014-10-13"
}]
}
}, {
"_ref": "84dd046c6695e32322d842f5",
"data": {
"values": []
}
}]
}
I did write the method updateProject
public bool updateProject(Project pro, Project dbPro)
{
var collection = db.GetCollection<BsonDocument>("projects");
var filter = Builders<BsonDocument>.Filter.Eq("_id", dbPro.Id);
var update = Builders<BsonDocument>.Update.Set("tasks", pro.Tasks);
var result = collection.UpdateOne(filter, update);
if (result.IsModifiedCountAvailable)
{
if (result.ModifiedCount == 1)
{
return true;
}
}
return false;
}
And thats how a project does look like in c#.
class Project{
public string id;
public List<Task> Tasks;
}
class Task{
public string id;
public List<Value> Values;
}
class Value{
public String key;
public String value;
}
but i cant figure out how i can go deeper to find the searched id.

Related

Is HashSet of a HashSet<T> the right data model here?

I'm managing a data structure that looks like the following
[
{
"name": "Yada yada",
"dataModels": [
{
"entity": "Table",
"columns": [
[
{
"column": "ColumnA",
"value": " \"StringA\""
},
{
"column": "ColumnB",
"value": " \"StringB\""
}
],
...,
[
{
"column": "ColumnA",
"value": " \"StringA\""
},
{
"column": "ColumnB",
"value": " \"StringB\""
}
],
...
]
}
]
}
]
Every object in the columns list is a HashSet of ColumnValues, a class I created and is defined the following way:
public class ColumnValues
{
private string column;
private string value;
public ColumnValues(string col, string val)
{
column = col;
value = val;
}
public string Column
{
get {return column;}
}
public string Value
{
get {return value;}
}
public override bool Equals(object obj)
{
return obj is ColumnValues values &&
column == values.column &&
value == values.value &&
Column == values.Column &&
Value == values.Value;
}
public override int GetHashCode()
{
return HashCode.Combine(column, value, Column, Value);
}
}
So far, so good. However the issue is that in columns, I'm having duplicates of lists. columns is a field in DataModel, another class:
public class DataModel
{
private string entity;
private List<HashSet<ColumnValues>> columns;
private string rule;
public DataModel(string entityName, List<HashSet<ColumnValues>> columnList)
{
entity = entityName;
columns = columnList;
}
public string Entity
{
get { return entity; }
}
public List<HashSet<ColumnValues>> Columns
{
get { return columns; }
set { columns = value; }
}
public string Rule
{
set { rule = value; }
}
}
I'm not understanding why the Set is allowing the existence of duplicates.
I do add that I'm returning the columns list after applying Distinct().ToList():
var dataModels = new List<DataModel>();
GatherColumns(code.Syntax);
dataModels.ForEach(dataModel => dataModel.Columns = dataModel.Columns.Distinct().ToList());
return dataModels;
TIA!
EDIT:
As per Tim's comment, I've provided the override methods Equals and GetHashCode.
I've also decided to define Columns in DataModel as a List of HashSets.
However, unfortunately the result hasn't changed.
EDIT N°2:
I've decided to create a class implementing the IEqualityComparer interface. However, little effect so far:
public class ColumnValuesComparer : IEqualityComparer<HashSet<ColumnValues>>
{
public bool Equals(HashSet<ColumnValues> c1, HashSet<ColumnValues> c2)
{
return c1.Equals(c2);
}
public int GetHashCode(HashSet<ColumnValues> obj)
{
return obj.GetHashCode();
}
}
Used here:
var dataModels = new List<DataModel>();
GatherColumns(code.Syntax);
ColumnValuesComparer comparer = new ColumnValuesComparer();
dataModels.ForEach(dataModel => dataModel.Columns = dataModel.Columns.Distinct(comparer).ToList());
return dataModels;
At this point I'm pretty much stuck, and don't know where to go moving forward.
After a bit of searching a documentation, I fell upon the concept of SetComparer.
They allow me to create objects that evaluate deep nested equality within HashSets.
So, when I try to create my HashSet of HashSets, I must pass that method:
var set = new HashSet<HashSet<ColumnValues>>(HashSet<ColumnValues>.CreateSetComparer());
set.Add(columnValues);

NJsonSchema C# - Change Generated Value Type

I am using NJsonSchema CsharpGenerator 10.1.24 and have the below schema I am using to generate a POCO:
"description": "schema validating people and vehicles",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [ "oneOf" ],
"properties": { "oneOf": [
{
"firstName": {"type": "string"},
"lastName": {"type": "string"},
"sport": {"type": "string"}
},
{
"vehicle": {"type": "string"},
"price":{"type": "number"}
}
]
}
}
How can I get the generated C# class to have a decimal type for price instead of the default double?
public double Price { get; set;}
I tried using a custom static method with the generator settings JsonSerializerSettingsTransformationMethod property but nothing changed.
You can try this,
Create CustomTypeResolver
public class CustomTypeResolver : CSharpTypeResolver
{
...
public override string Resolve(JsonSchema schema, bool isNullable, string typeNameHint)
{
if (schema == null)
{
throw new ArgumentNullException(nameof(schema));
}
schema = GetResolvableSchema(schema);
if (schema == ExceptionSchema)
{
return "System.Exception";
}
var type = schema.ActualTypeSchema.Type;
if (type.HasFlag(JsonObjectType.Number))
{
return isNullable ? "decimal?" : "decimal"; ;
}
return base.Resolve(schema, isNullable, typeNameHint);
}
...
}
Generate the class,
var jsonSchema = File.ReadAllText("json1.json");
var schema = JsonSchema.FromJsonAsync(jsonSchema).GetAwaiter().GetResult();
var settings = new CSharpGeneratorSettings();
var typeResolver = new CustomTypeResolver(settings);
var generator = new CSharpGenerator(schema, settings, typeResolver);
var code = generator.GenerateFile();
#tontonsevilla, How would you return both objects under oneOfs to be included in C# POCO? In example above by #user2966445 it will only generate the first item under oneOfs for me, I will only get the POCO with firstName, lastName and sport properties in the POCO & not include vehicle and price. So, when deseriazing the json to POCO it blows up if json payload contains vehicle & price.
One thing I noticed in the NJsonSchema.JsonSchema objects "Resolve" method, it also calls "RemoveNullability" method internally and this code which only returns first item in the oneOfs and not sure how to get around it.
public JsonSchema RemoveNullability( JsonSchema schema )
{
return schema.OneOf.FirstOrDefault( ( JsonSchema o ) => !o.IsNullable( SchemaType.JsonSchema ) ) ?? schema;
}

How can I parse instance properties by using json data?

I try to parse json data to List<Employee> instance. But I don't want to use Json-to-C# tool for creating a shadow from json pattern. I want to take values only. Maybe I can use keys to take values (Employee). I want to fill a List of Employee.
My Json:
{
"type":"SUCCESS",
"msg":"Container RBFFiyatlama2_1.0.1 successfully called.",
"result":{
"execution-results":{
"results":[
{
"value":2,
"key":""
},
{
"value":{
"com.myteam.rbffiyatlama2.Employee":{
"salary":2400.0,
"age":35,
"cofactor":0.2
}
},
"key":"Employee0"
},
{
"value":{
"com.myteam.rbffiyatlama2.Employee":{
"salary":4800.0,
"age":35,
"cofactor":0.2
}
},
"key":"Employee1"
}
],
"facts":[
{
"value":{
"org.drools.core.common.DefaultFactHandle":{
"external-form":"0:88:1504512052:1504512052:160:DEFAULT:NON_TRAIT:com.myteam.rbffiyatlama2.Employee"
}
},
"key":"Employee0"
},
{
"value":{
"org.drools.core.common.DefaultFactHandle":{
"external-form":"0:89:213603577:213603577:159:DEFAULT:NON_TRAIT:com.myteam.rbffiyatlama2.Employee"
}
},
"key":"Employee1"
}
]
}
}
}
How can I fill Employee without creating any C# class by using above json.
public class Employee
{
public int age { get; set; }
public double cofactor { get; set; }
public int salary { get; set; }
}
You could use dynamics. The following should do what you're after and it's all native:
string jsonString = YourGetJsonStringMethod();
List<Employee> employees = new List<Employee>();
dynamic data = System.Web.Helpers.Json.Decode(jsonString);
dynamic results = data["result"]["execution-results"]["results"];
if (results.Length > 1)
{
for (var i = 1; i < results.Length; i++)
{
var dynamicEmployee = results[i]["value"]["com.myteam.rbffiyatlama2.Employee"];
dynamicEmployee["salary"] = (int) dynamicEmployee["salary"];
var encoded = System.Web.Helpers.Json.Encode(dynamicEmployee);
employees.Add(System.Web.Helpers.Json.Decode<Employee>(encoded));
}
}
You will obviously need to include System.Web.Helpers in your references, which you can find under Assemblies > Extensions in your Visual Studio Reference Manager.
Bear in mind that this code may raise an exception when you're debugging. If so, refer to this question for the solution.
This code "just works". I will leave it to you to do validation, null-checking and exception catching.

Change status value from int to string

I have a status property with int values in array of objects. Below is the output of array of objects.
[
{
"enterpriseServiceId": 1,
"enterpriseServices": {},
"status": 3,
"id": 1,
"createdOn": "2017-12-29T17:58:15.4855946",
"createdBy": "System",
"modifiedOn": "2017-12-29T17:58:15.4855946",
"modifiedBy": "System"
},
{
"enterpriseServiceId": 2,
"enterpriseServices": {},
"status": 1,
"id": 2,
"createdOn": "2017-12-29T17:58:15.4855946",
"createdBy": "System",
"modifiedOn": "2017-12-29T17:58:15.4855946",
"modifiedBy": "System"
}
]
The status property is enum value type. I am trying to convert that to string value so it is easier to read when it is returned in output.
Below is my code that gets the data from sql server database.
ENUM
namespace CoreLibrary.Models.Enums
{
public static class Common
{
public enum Status
{
Active = 1,
InActive,
Completed,
Failed,
InProgress,
Pause,
Resume,
Skip,
Running
}
}
}
Entity Model:
namespace CoreLibrary.Models.Entities
{
public class Deployments : BaseProperties
{
public int EnterpriseServiceId { get; set; }
[ForeignKey("EnterpriseServiceId")]
public virtual EnterpriseServices EnterpriseServices { get; set; }
public Common.Status Status { get; set; }
}
}
Method that retrieves data from database:
[HttpGet("~/api/Deployments/GetWithJoins")]
public JsonResult GetWithJoins()
{
try
{
// includeList for including data from external tables (JOIN Query)
var includeList = new List<Expression<Func<Deployments, object>>>();
includeList.Add(d => d.EnterpriseServices);
IEnumerable<Deployments> result = _repository.GetByIdWithJoins(queryable: includeList).ToList();
return Json(result);
}
catch (Exception ex)
{
var innerException = ex.InnerException == null ? null : ex.InnerException.Message.ToString();
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { status = "failed", message = ex.Message.ToString(), innerException = innerException });
}
}
The result variable returns the output I shared at very beginning of this post. I am trying to convert status to return string value instead of int.
I am not sure if thats even possible or it is the right way to output of status int to string value?
I tried online, but I havent found a solution to my requirement. I would appreciate any help you guys can give. :)
When we call JSON(someObject), ASP.NET uses its JavaScriptSerializer to create a JsonResult. The default configuration of the JavaScriptSerializer converts enums to their integer representation.
We can configure the serializer to use a string representation of enums instead. There are details on how to do that here: JSON serialization of enum as string
If that approach does not appeal, then you can use LINQ to map to an anonymous object using Enum.ToString(). Here is an example:
var result = deployments.Select(x =>
{
return new
{
Status = x.Status.ToString(),
x.EnterpriseServiceId
};
});
While the LINQ approach will work, it might lead to maintenance problems in the long-term.

how to get data from json [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
How do i parse json?
Please tell me the way to deserialize the json data in asp.net c#.
Actually I have a json data with two objects like:
{
"errstr": "All downloded vedios ",
"errcode": 0,
"result": {
"videos": [
{
"id": "22",
"name": "Ashley",
"price": "0.49",
"size": "3712310"
}
],
"trailer": [
{
"id": "1",
"trailer_name": "charl1",
"status": "1"
},
{
"id": "2",
"trailer_name": "charl2",
"status": "1"
}
]
}
}
Here I have two objects videos and trailer. Please tell me the process to get get these data in my code.
you need to create a class with nested members
for example json file
{
"GeminiURL":"https://gemini.com/Gemini"
,"Language":"en"
,"Log":{"Debug":true,"Info":true,"Warn":true,"FileName":"d:\\temp\\tfsgemini.log"}
}
is serializaed and deserialized with c# class
public class Settings
{
public string GeminiURL;
private LogSettings _log;
public LogSettings Log
{
get { return _log = _log ?? new LogSettings(); }
set { _log = value; }
}
public string Language;
public Settings()
{
// defaule settings can be assigned here;
}
}
public class LogSettings
{
public bool Debug;
public bool Info = true;
public bool Warn = true;
public string FileName;
}
and the deserialization code looks like:
public static T Load(string fileName)
{
T t = new T();
if (File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
else
Save(t);
return t;
}
JSON .NET - http://json.codeplex.com/

Categories