Mondodb C# save dictionary with array value - c#

I have a mongo collection: Fieldset . Fieldset has List if embedded object Field.
Field has a Dictionary<string, object> Config, I want to be free about the value of this dictionary.
public class Fieldset
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Slug { get; set; }
[BsonElement("Fields")]
public List<Field> Fields { get; set; }
}
public class Field
{
[BsonElement("Config")]
public Dictionary<string, object> Config { get; set; }
}
this is an example of value i want to put in. some sort of key value collection:
When I save, this is the value I have in the mongo.

Hmm. It worked like supposed to work>
static void Main(string[] args)
{
var client = new MongoClient();
var database = client.GetDatabase("SO3");
var collection = database.GetCollection<Fieldset>("jobject");
var id = new BsonObjectId(ObjectId.GenerateNewId()).ToString();
var field =
new Field
{
Config = new Dictionary<string, object> {{"value", "item1key"}, {"lable", "item1value"}}
};
var field2 =
new Field
{
Config = new Dictionary<string, object> {{"value", "item2key"}, {"lable", "item2value"}}
};
var fieldset = new Fieldset
{
Id = id,
Slug = "aa",
Fields = new List<Field>
{
field,
field2
}
};
collection.InsertOne(fieldset);
}
{ "_id" : ObjectId("5c55b972ceb9443d385de936"), "Slug" : "aa", "Fields" : [ { "Config" : { "value" : "item1key", "lable" : "item1value" } }, { "Config" : { "value" : "item2key", "lable" : "item2value" } } ] }

Related

get data from json array string to an string variable

I get from another app an HTTP request with a JSON payload like this:
{
"reportName": "myfile",
"type_1": "pdf",
"paramm": [
{ "REF": "value1"},
{ "whatevervalue2": "whatevervalue2" }
]
}
I receive the data and try to process it. I created a class to get the data from the JSON:
public class ReportId
{
public string reportName { get; set; }
public string type_1 { get; set; }
public object[] paramm { get; set; }
}
And here is the method where I process all the data on the API controller:
[HttpPost]
public IActionResult generate([FromBody] ReportId jsonResult)
{
try
{
var reportName = jsonResult.reportName;
var type = jsonResult.type_1;
var recParam = jsonResult.paramm;
//....
List<ReportParameter> parameters = new List<ReportParameter>();
foreach (var t in recParam)
{
string[] paramName;
paramName = t.ToString().Split(":");
parameters.Add(new ReportParameter()
{
Name = paramName[0],
Labels = new List<string>() { paramName[1] },
Values = new List<string>() { paramName[1] }
});
}
reportWriter.SetParameters(parameters);
//....
}
catch
{
return null;
}
}
I got no problems with reportName and type_1 but on paramm it gets kinda wonky. I need to get the values of that array from the JSON. I do manage to get them, but with "all the format". For example, after the split on the first one I would get:
"{\r\n \"REF\""
" \"value1\"\r\n}"
Is there any more elegant way to get the values from that paramm array without having to replace the characters that are not part of the "real" string?
Thanks in advance.
[EDIT for clarification]
On the JSON I'll get multiple parameters:
"paramm": [
{ "parameter1": "value1" },
{ "parameter2": "value2" },
{ "parameter3": "value3" }
]
The parameter name could be any word and the value could be any as well. Those parameters are being sent to an RDL to filter some queries, so I need to get the name (parameter1, 2, 3...) and its value and add it as a parameter on the iteration of each.
Yes, there is an easier way.
In your ReportId class, change the paramm member to be a List<Dictionary<string, string>> instead of object[].
public class ReportId
{
...
public List<Dictionary<string, string>> paramm { get; set; }
}
Then, in your generate method you can just get the key and value from each dictionary instead of needing to do string manipulation:
List<ReportParameter> parameters = new List<ReportParameter>();
foreach (var dict in recParam)
{
var kvp = dict.First();
parameters.Add(new ReportParameter()
{
Name = kvp.Key,
Labels = new List<string>() { kvp.Value },
Values = new List<string>() { kvp.Value }
});
}
I guess, Your ReportId class should be like this. I hope this will work.
public partial class ReportId
{
[JsonProperty("reportName")]
public string ReportName { get; set; }
[JsonProperty("type_1")]
public string Type1 { get; set; }
[JsonProperty("paramm")]
public Paramm[] Paramm { get; set; }
}
public partial class Paramm
{
[JsonProperty("REF", NullValueHandling = NullValueHandling.Ignore)]
public string Ref { get; set; }
[JsonProperty("whatevervalue2", NullValueHandling = NullValueHandling.Ignore)]
public string Whatevervalue2 { get; set; }
}

CsvHelper define custom mapping for a column

I am trying to have a column not provided in the CSV file populated using CSVHelper.
This is an example of the CSV I need to import
Id
10
123
45
213
The class I am trying to deserialize to is this one:
public class Foo {
public int Id { get; set }
public string Name { get; set }
}
With the default configuration I get this error:
CsvHelper.HeaderValidationException: 'Header with name 'Name' was not found.
I would like to have the possibility to define a mapper so that the column Name could be populated by the parser (e.g. by providing a dictionary of values). Any way to do this?
Thanks
---------- EDIT
Just to clarify, the idea is to have something like a converter that, associated to a field, would be used to decode the Id to the Name
public class NameConverter
{
public NameConverter()
{
employeesList = new Dictionary<int, string>()
{
{ 10, "Mary" },
{ 45, "Mike" },
{ 123, "Jack" },
{ 213, "Suzanne" },
};
}
IDictionary<int, string> employeesList;
public string GetValue(int id) => employeesList[id];
}
The alternative, I would imagine, is to ignore the Name field as suggested and inject the NameConverter in the Foo class and make the Name a get only property.
void Main()
{
var s = new StringBuilder();
s.AppendLine("Id");
s.AppendLine("45");
s.AppendLine("123");
using (var reader = new StringReader(s.ToString()))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.RegisterClassMap<FooMap>();
csv.GetRecords<Foo>().ToList().Dump();
}
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FooMap : ClassMap<Foo>
{
public FooMap()
{
var nameConverter = new NameConverter();
Map(m => m.Id);
Map(m => m.Name).ConvertUsing(row => nameConverter.GetValue(row.GetField<int>(nameof(Foo.Id))));
}
}
public class NameConverter
{
public NameConverter()
{
employeesList = new Dictionary<int, string>()
{
{ 10, "Mary" },
{ 45, "Mike" },
{ 123, "Jack" },
{ 213, "Suzanne" },
};
}
IDictionary<int, string> employeesList;
public string GetValue(int id) => employeesList[id];
}
Output:

How to find a specific value in an IDictionary<string, object>?

This IDictionary<string, object> contains user data I'm logging into mongodb. The issue is the TValue is a complex object. The TKey is simply the class name.
For example:
public class UserData
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Admin NewAdmin { get; set; }
}
public class Admin
{
public string UserName { get; set; }
public string Password { get; set; }
}
Currently, I'm trying to iterate through the Dictionary and compare types but to no avail. Is there a better way of doing this or am I missing the mark?
var argList = new List<object>();
foreach(KeyValuePair<string, object> kvp in context.ActionArguments)
{
dynamic v = kvp.Value;
//..compare types...
}
Just use OfType<>(). You don't even need the key.
public static void Main()
{
var d = new Dictionary<string,object>
{
{ "string", "Foo" },
{ "int", 123 },
{ "MyComplexType", new MyComplexType { Text = "Bar" } }
};
var s = d.Values.OfType<string>().Single();
var i = d.Values.OfType<int>().Single();
var o = d.Values.OfType<MyComplexType>().Single();
Console.WriteLine(s);
Console.WriteLine(i);
Console.WriteLine(o.Text);
}
Output:
Foo
123
Bar
Link to Fiddle

Noob using C# classes and accessing them

I'm working with JSON (using json.net) and a C# console application and I am trying to set some values for a JSON POST to a server.
I can set some of the values, but accessing others is giving me fits.
My JSON looks like this:
{
"params" : [
{
"url" : "sys/login/user",
"data" : [
{
"passwd" : "pwd",
"user" : "user"
}
]
}
],
"session" : 1,
"id" : 1,
"method" : "exec"
}
I ran that through json2csharp and it generated me the following classes.
public class Datum
{
public string passwd { get; set; }
public string user { get; set; }
}
public class Param
{
public string url { get; set; }
public List<Datum> data { get; set; }
}
public class RootObject
{
public List<Param> #params { get; set; }
public string session { get; set; }
public int id { get; set; }
public string method { get; set; }
}
I then created this object for testing in my Main method
RootObject temp = new RootObject()
temp.id = 1;
temp.method = "exec";
temp.session = "1";
and those parameters get set just fine.
I can also set the URL param using the following:
temp.#params.Add(new Param { url = "some/url", });
It is setting the public List<Datum> data { get; set; } item that is the problem. I cannot figure out how to access that and set the user and password items.
If I add this to the Param class I can set the values, but this seems to be the wrong way/place to me.
public Param()
{
data = new List<Datum>();
data.Add(new Datum { user = "user", passwd = "pass" });
}
Well, you create your RootObject like this:
RootObject temp = new RootObject()
temp.id = 1;
temp.method = "exec";
temp.session = "1";
Then you create the params list and fill it with one Param:
temp.#params = new List<Param>();
temp.#params.Add(new Param { url = "some/url" });
You can then set the data for one param in the list (in this example the first one):
temp.#params[0].data = new List<Datum>();
temp.#params[0].data.Add(new Datum { user = "user", passwd = "pass" });
This is necessary, because #params is a list of Param objects. You could also fill the data when creating the Param instance before adding it to the list (easier, because you otherwise need to know the list index).
temp.#params = new List<Param>();
Param p = new Param { url = "some/url" };
p.data = new List<Datum>();
p.data.Add(new Datum() { ... });
temp.#params.Add(p);
Usually you'd change change the default constructors to initialize the lists already and prevent the list instances from being replaced by changing the properties to read-only, but that might not work well with JSON deserialization, so you really need to try this. It would look like this:
public class Param
{
public Param()
{
data = new List<Datum>();
}
public string url { get; set; }
public List<Datum> data { get; private set; }
}
public class RootObject
{
public RootObject()
{
#params = new List<Param>();
}
public List<Param> #params { get; private set; }
public string session { get; set; }
public int id { get; set; }
public string method { get; set; }
}

How to add object of type dictionary as BsonElement in BsonDocument

Well I am trying to perform insert batch operation. For that I am creating an array of BsonDocuemt. To each BsonDocument In array, I am adding BsonElements.
Question Class (Model):
public class Question
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string QuestionName { get; set; }
public Dictionary<string, VariableDetails> Rules { get; set; }
public List<Question> QuestionsList { get; set; }
}
public class VariableDetails
{
public string variableType { get; set; }
public string min { get; set; }
public string max { get; set; }
}
Now I am trying to form array of BsonDocuemts as follows:
public void batchInsert(Question Model)
{
_collection = _db.GetCollection<Question>("Question");
BsonDocument[] batch = new BsonDocument[Model.QuestionsList.Count];
int count = 0;
foreach (Question question in Model.QuestionsList )
{
BsonDocument bsonDoc = new BsonDocument();
bsonDoc.Add(new BsonElement("QuestionName", question.QuestionName ));
//Following line is in error
bsonDoc.Add(new BsonElement("Rules", question.Rules));
//Argument type 'Systems.Collections.Generic.Dictionary<string, VariableDetails>' is not assignable to parameter type 'MongoDB.Bson.BsonValue'.
batch[count] = bsonDoc;
count++;
}
_collection.InsertBatch(batch);
}
I am able to add property of type string as BsonElement in BsonDocument, Not able to do so with property of type Dictionary.
I want the final insert in db should be like:
{
"_id" : ObjectId("54757796bb63bc08b481ad86"),
"Name" : "Question1",
"Rules" : {
"a1" : {
"variableType" : "1dPI",
"min" : "1",
"max" : "9"
},
"a2" : {
"variableType" : "1dPI",
"min" : "1",
"max" : "9"
}
}
},
{
"_id" : ObjectId("54757796bb63bc08b481ad86"),
"Name" : "Question2",
"Rules" : {
"d1" : {
"variableType" : "1dPI",
"min" : "1",
"max" : "9"
},
"f3" : {
"variableType" : "1dPI",
"min" : "1",
"max" : "9"
}
}
}
My question is how can I add property of type Dictionary as BsonElement in BsonDocuemt?
I just needed to add nested BsonDocument as an element to parent BsonDocument. That's it!
public void batchInsert(Question Model)
{
_collection = _db.GetCollection<Question>("Question");
BsonDocument[] batch = new BsonDocument[Model.QuestionList.Count];
int count = 0;
foreach (Question question in Model.QuestionList)
{
BsonDocument rulesBsonDoc = new BsonDocument();
foreach (KeyValuePair<string, VariableDetails> qTemp in question.Rules)
{
string variableName = qTemp.Key;
VariableDetails variableDetails = qTemp.Value;
string variableType = variableDetails.variableType;
string min = variableDetails.min;
string max = variableDetails.max;
BsonDocument childBsonDoc = new BsonDocument();
childBsonDoc.Add(new BsonElement("variableType", variableType));
childBsonDoc.Add(new BsonElement("min", min));
childBsonDoc.Add(new BsonElement("max", max));
rulesBsonDoc.Add(new BsonElement(variableName, childBsonDoc));
}
BsonDocument bsonDoc = new BsonDocument();
bsonDoc.Add(new BsonElement("Name", question.Name));
bsonDoc.Add(new BsonElement("Rules", rulesBsonDoc));
batch[count] = bsonDoc;
count++;
}
_collection.InsertBatch(batch);
}

Categories

Resources