Elasticsearch - C# NEST - Change Dictionary<K,V> mapping behavior - c#

I want to change the mapping behavior in C# NEST.
My class looks like:
public class Vector
{
public Guid Guid { get; set; } = Guid.Empty;
public Dictionary<string, double> Entries { get; set; }
}
The default auto mapping (e.g.)
var client = new ElasticClient(settings);
client.Map<Vector>(m => m.AutoMap());
// index sample data
client.Index(new Vector { Guid = Guid.NewGuid(),Entries = new Dictionary <string, double> { {"A", 5.3}, {"B", 1.3}, {"C", 7.7}}});
client.Index(new Vector { Guid = Guid.NewGuid(), Entries = new Dictionary<string, double> { {"D", 2.3}, {"B", 8.0}, {"F", 5.1}}});
client.Index(new Vector { Guid = Guid.NewGuid(), Entries = new Dictionary<string, double> { {"A", 2.2}, {"B", 0.3}, {"F", 5.9}}});
generates the following Elasticsearch-mapping:
"mappings" : {
"vector" : {
"properties" : {
"entries" : {
"properties" : {
"A" : {
"type" : "float"
},
"B" : {
"type" : "float"
},
"C" : {
"type" : "float"
},
"D" : {
"type" : "float"
},
"F" : {
"type" : "float"
}
}
},
"guid" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
As you can see - A, B, C, D, F are float-properties. If you have to many type properties in ES - it will slow down the whole server. So I want to map the dictionary to a key-value-pair, like this:
"mappings" : {
"vector" : {
"properties" : {
"entries" : {
"properties" : {
"key" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"value" : {
"type" : "float"
}
}
}
...
}
}
}
So my current solution is:
public class Vector
{
public Guid Guid { get; set; } = Guid.Empty;
public KeyValuePair<string, double>[] Entries { get; set; }
}
// ...
client.Index(new Vector { Guid = Guid.NewGuid(), entries = dictionary.ToArray() });
Is there a better solution without .ToArray(); or build a nested class?

Related

Convert generic Json with multiple nested array to a Datatable C#

I need help, I need a function that recive a Json and returns a Datatable, any input can come in Json format so I can't use a object.
My problem is when the Json comes with multiple Arrays nested in the response (the Json can have any format, it can come without Arrays or it can come with 1 or more Arrays), any idea how to make this possible? I need the algorithm to be as generic as possible. Thanks
I leave an example input and what I expect to get
public const string ResponseThreeArrays = #"{
""key1"": ""val1"",
""key2"": {
""key2-1"":
[
{
""key2-arr1-1"": ""val2-arr1-1(1)"",
""key2-arr1-2"":
[
{
""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(1)(1)"",
""key2-arr1-arr2-2"" :
[
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(1)(1)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(1)(1)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(1)(1)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(1)(2)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(1)(2)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(1)(2)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(1)(3)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(1)(3)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(1)(3)""
}
],
""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(1)(1)""
},
{
""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(1)(2)"",
""key2-arr1-arr2-2"" :
[
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(2)(1)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(2)(1)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(2)(1)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(2)(2)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(2)(2)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(2)(2)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(2)(3)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(2)(3)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(2)(3)""
}
],
""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(1)(2)""
}
]
},
{
""key2-arr1-1"": ""val2-arr1-1(2)"",
""key2-arr1-2"":
[
{
""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(2)(1)"",
""key2-arr1-arr2-2"" :
[
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(1)(1)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(1)(1)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(1)(1)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(1)(2)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(1)(2)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(1)(2)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(1)(3)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(1)(3)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(1)(3)""
}
],
""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(2)(1)""
},
{
""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(2)(2)"",
""key2-arr1-arr2-2"" :
[
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(2)(1)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(2)(1)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(2)(1)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(2)(2)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(2)(2)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(2)(2)""
},
{
""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(2)(3)"",
""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(2)(3)"",
""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(2)(3)""
}
],
""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(2)(2)""
}
]
}
],
""key2-2"" : ""val2-2""
},
""key3"": ""val3""
}";
And this is what I expect obtain:
Datatable expected
Use Cinchoo ETL - an open source library to do such conversion easily. (Not sure, this meets your requirement)
using (var r = ChoJSONReader.LoadText(ResponseThreeArrays)
.ErrorMode(ChoErrorMode.IgnoreAndContinue)
)
{
var dt = r.FlattenBy("key2", "key2-1", "key2-arr1-2", "key2-arr1-arr2-2").AsDataTable();
dt.Print();
}
Output:
key1,key3,key2-2,key2-arr1-1,key2-arr1-arr2-1,key2-arr1-arr2-3,key2-arr1-arr2-arr3-1,key2-arr1-arr2-arr3-2,key2-arr1-arr2-arr3-3
val1,val3,val2-2,val2-arr1-1(1),val2-arr1-arr2-1(1)(1),val2-arr1-arr2-3(1)(1),val2-arr1-arr2-arr3-1(1)(1)(1),val2-arr1-arr2-arr3-2(1)(1)(1),val2-arr1-arr2-arr3-3(1)(1)(1)
val1,val3,val2-2,val2-arr1-1(1),val2-arr1-arr2-1(1)(1),val2-arr1-arr2-3(1)(1),val2-arr1-arr2-arr3-1(1)(1)(2),val2-arr1-arr2-arr3-2(1)(1)(2),val2-arr1-arr2-arr3-3(1)(1)(2)
val1,val3,val2-2,val2-arr1-1(1),val2-arr1-arr2-1(1)(1),val2-arr1-arr2-3(1)(1),val2-arr1-arr2-arr3-1(1)(1)(3),val2-arr1-arr2-arr3-2(1)(1)(3),val2-arr1-arr2-arr3-3(1)(1)(3)
val1,val3,val2-2,val2-arr1-1(1),val2-arr1-arr2-1(1)(2),val2-arr1-arr2-3(1)(2),val2-arr1-arr2-arr3-1(1)(2)(1),val2-arr1-arr2-arr3-2(1)(2)(1),val2-arr1-arr2-arr3-3(1)(2)(1)
val1,val3,val2-2,val2-arr1-1(1),val2-arr1-arr2-1(1)(2),val2-arr1-arr2-3(1)(2),val2-arr1-arr2-arr3-1(1)(2)(2),val2-arr1-arr2-arr3-2(1)(2)(2),val2-arr1-arr2-arr3-3(1)(2)(2)
val1,val3,val2-2,val2-arr1-1(1),val2-arr1-arr2-1(1)(2),val2-arr1-arr2-3(1)(2),val2-arr1-arr2-arr3-1(1)(2)(3),val2-arr1-arr2-arr3-2(1)(2)(3),val2-arr1-arr2-arr3-3(1)(2)(3)
val1,val3,val2-2,val2-arr1-1(2),val2-arr1-arr2-1(2)(1),val2-arr1-arr2-3(2)(1),val2-arr1-arr2-arr3-1(2)(1)(1),val2-arr1-arr2-arr3-2(2)(1)(1),val2-arr1-arr2-arr3-3(2)(1)(1)
val1,val3,val2-2,val2-arr1-1(2),val2-arr1-arr2-1(2)(1),val2-arr1-arr2-3(2)(1),val2-arr1-arr2-arr3-1(2)(1)(2),val2-arr1-arr2-arr3-2(2)(1)(2),val2-arr1-arr2-arr3-3(2)(1)(2)
val1,val3,val2-2,val2-arr1-1(2),val2-arr1-arr2-1(2)(1),val2-arr1-arr2-3(2)(1),val2-arr1-arr2-arr3-1(2)(1)(3),val2-arr1-arr2-arr3-2(2)(1)(3),val2-arr1-arr2-arr3-3(2)(1)(3)
val1,val3,val2-2,val2-arr1-1(2),val2-arr1-arr2-1(2)(2),val2-arr1-arr2-3(2)(2),val2-arr1-arr2-arr3-1(2)(2)(1),val2-arr1-arr2-arr3-2(2)(2)(1),val2-arr1-arr2-arr3-3(2)(2)(1)
val1,val3,val2-2,val2-arr1-1(2),val2-arr1-arr2-1(2)(2),val2-arr1-arr2-3(2)(2),val2-arr1-arr2-arr3-1(2)(2)(2),val2-arr1-arr2-arr3-2(2)(2)(2),val2-arr1-arr2-arr3-3(2)(2)(2)
val1,val3,val2-2,val2-arr1-1(2),val2-arr1-arr2-1(2)(2),val2-arr1-arr2-3(2)(2),val2-arr1-arr2-arr3-1(2)(2)(3),val2-arr1-arr2-arr3-2(2)(2)(3),val2-arr1-arr2-arr3-3(2)(2)(3)
Sample fiddle: https://dotnetfiddle.net/wnacwN
Disclaimer: I'm the author of this library.
I leave here what I have so far, #Cinchoo
public DataTable MapJson(string json)
{
var jo = JToken.Parse(json);
var stringReader = new StringReader(MakeConfigString(jo));
var serializer = new XmlSerializer(typeof(DataTableConfig));
var config = (DataTableConfig)serializer.Deserialize(stringReader);
var dataTable = new DataTable();
foreach (var p in config.Property)
{
dataTable.Columns.Add(p.Name);
}
var regex = new Regex(Regex.Escape("*"));
var count = 0;
if (jo is JArray)
{
count = jo.Count();
}
else if (jo is JObject jsonLinq)
{
count = jsonLinq.Descendants().FirstOrDefault(d => d is JArray)?.Count() ?? 1;
}
var dataCollection = Enumerable.Range(0, count)
.Select(x => config.Property
.Select(prop => new KeyValuePair<string, List<string>>
(
prop.Name,
jo.SelectTokens(regex.Replace(prop.Path, x.ToString(), 1)).Select(c => c.Value<string>()).ToList())
));
foreach (var data in dataCollection)
{
var countMax = data.Select(x => x.Value).Max(x => x.Count);
for (var i = 0; i < countMax; i++)
{
var innerList = new List<object>();
foreach (var prop in config.Property)
{
var currentData = data.Where(x => x.Key == prop.Name).SelectMany(x => x.Value).ToList();
if (currentData.Any())
{
if (i >= currentData.Count)
{
innerList.Add(currentData.Last());
}
else
{
innerList.Add(currentData[i]);
}
}
else
{
innerList.Add("");
}
}
dataTable.Rows.Add(innerList.ToArray());
}
}
return dataTable;
}
private string MakeConfigString(JToken json)
{
var result = #"<DataTableConfig Name='DataTable'>";
foreach (var col in this.ApiConnectorsColumns)
{
var path = json is JArray ? col.PathNode.Replace(".Columns", "[*]") : col.PathNode.Remove(0, 9);
var temp = $"<Property Name='{col.ColumnName}' Path='{path}'/>";
result += temp;
}
result += "</DataTableConfig>";
return result;
}
[XmlRoot(ElementName = "Property")]
public class Property
{
[XmlAttribute(AttributeName = "Name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "Path")]
public string Path { get; set; }
}
[XmlRoot(ElementName = "DataTableConfig")]
public class DataTableConfig
{
[XmlElement(ElementName = "Property")]
public List<Property> Property { get; set; }
[XmlAttribute(AttributeName = "Name")]
public string Name { get; set; }
}

How to create custom serializer for values in dictionary?

I have the following class:
public class Farm
{
public string County {get;set;}
public Dictionary<string, object> FarmItems {get;set;}
}
I need to implement a custom serializer/deserializer that, if it's a integer in the value, store it in the DB as a string and then deserialize it back to a integer
I've looked at the docs and they gave details on how to do it for single values but not for dictionaries https://mongodb.github.io/mongo-csharp-driver/2.12/reference/bson/serialization/
Also, the docs don't mention how to implement it, do I just add an attribute after creating my class like so:
[BsonSerializer(typeof(MyCustomSerializer))]
public Dictionary<string, object> FarmItems {get;set;}
here you go:
public class MyDictionarySerialzer : SerializerBase<Dictionary<string, object>>
{
public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, Dictionary<string, object> dictionary)
{
if (dictionary == null)
{
ctx.Writer.WriteStartArray();
ctx.Writer.WriteEndArray();
return;
}
ctx.Writer.WriteStartArray();
foreach (var kvPair in dictionary)
{
ctx.Writer.WriteStartDocument();
ctx.Writer.WriteName("k");
ctx.Writer.WriteString(kvPair.Key);
ctx.Writer.WriteName("v");
if (kvPair.Value is int)
ctx.Writer.WriteString(kvPair.Value.ToString());
else
BsonSerializer.Serialize(ctx.Writer, kvPair.Value);
ctx.Writer.WriteEndDocument();
}
ctx.Writer.WriteEndArray();
}
public override Dictionary<string, object> Deserialize(BsonDeserializationContext ctx, BsonDeserializationArgs args)
{
Dictionary<string, object> dict = new();
switch (ctx.Reader.CurrentBsonType)
{
case BsonType.Array:
foreach (var val in BsonSerializer.Deserialize<BsonArray>(ctx.Reader))
{
string key = val["k"].AsString;
object value = BsonSerializer.Deserialize<object>(val["v"].ToJson());
if (int.TryParse(value?.ToString(), out var parsedInt))
value = parsedInt;
dict.Add(key, value);
}
return dict;
default:
throw new BsonSerializationException("Unable to deserialize dictionary!");
}
}
}
if you are storing any complex entities in the dictionary values, you have to register (on app startup) that complex type with mongo driver like so (or deserialization will fail):
BsonClassMap.RegisterClassMap<ComplexItem>();
simply decorate the property like so:
public class Farm
{
[BsonSerializer(typeof(MyDictionarySerialzer))]
public Dictionary<string, object> FarmItems { get; set; }
}
example entity:
var example = new Farm
{
FarmItems = new Dictionary<string, object>()
{
{"empty",null },
{"string","test string" },
{"int",100 },
{"complex",new ComplexItem{ Age = 10, Name = "test" } }
}
};
it will be serialized to the db like so:
{
"FarmItems" : [
{
"k" : "empty",
"v" : null
},
{
"k" : "string",
"v" : "test string"
},
{
"k" : "int",
"v" : "100"
},
{
"k" : "complex",
"v" : {
"_t" : "ComplexItem",
"Name" : "test",
"Age" : 10
}
}
]
}

MongoDB HashTable Averages

I am using c#,along with MongoDB.
I have a class that can be resembled by this.
Its a sample, that represents something, please dont comment on the class design
[CollectionName("Venues")]
public class Venue
{
public string Name { get; set; }
public dictionary<string,object> Properties { get; set; }
}
var venue = new Venue
{
Name = "Venue 1",
Properties = new Dictionary<string,object>
{
{ "Chairs", "18" },
{ "Tables", "4" },
{ "HasWaterfall", true }
}
}
Assuming I have an object in a collection, that looks like that.
I would like to find out of it is possible to do two things.
1: Load from the database, only a single item from the dictionary,
currently I can only see how this can be done, by loading the entire
record from the database and then manually getting the value by key.
2: Determine the average of a single item within the database.
For example, across all records I would like to work out the average
chairs, again without loading all records and then doing it in memory with
linq etc....
Basically your sample document gets stored as a below JSON:
{
"_id" : ObjectId("..."),
"Name" : "Venue 1",
"Properties" : {
"Chairs" : "18",
"Tables" : "4",
"HasWaterfall" : true
}
}
This gives you a possibility to define a projection using dot notation:
var filter = Builders<Venue>.Filter.Eq(f => f.Name, "Venue 1");
var projection = Builders<Venue>.Projection.Include("Properties.Chairs");
List<BsonDocument> data = Col.Find(filter).Project(projection).ToList();
which returns below following BsonDocument:
{ "_id" : ObjectId("..."), "Properties" : { "Chairs" : "18" } }
To get the average you need to use $toInt operator introduced in MongoDB 4.0 to convert your values from string to int. Try:
var project = new BsonDocument()
{
{ "chairs", new BsonDocument() { { "$toInt", "$Properties.Chairs" } } }
};
var group = new BsonDocument()
{
{ "_id", "null" },
{ "avg", new BsonDocument() { { "$avg", "$chairs" } } }
};
var avg = Col.Aggregate().Project(project).Group(group).First();
here's an alternative way of doing it using MongoDB.Entities convenience library.
using System.Collections.Generic;
using System.Linq;
using MongoDB.Entities;
namespace StackOverflow
{
class Program
{
[Name("Venues")]
public class Venue : Entity
{
public string Name { get; set; }
public Dictionary<string, object> Properties { get; set; }
}
static void Main(string[] args)
{
new DB("test");
var venue1 = new Venue
{
Name = "Venue 1",
Properties = new Dictionary<string, object> {
{ "Chairs", 28 },
{ "Tables", 4 },
{ "HasWaterfall", true }
}
};
venue1.Save();
var venue2 = new Venue
{
Name = "Venue 2",
Properties = new Dictionary<string, object> {
{ "Chairs", 38 },
{ "Tables", 4 },
{ "HasWaterfall", true }
}
};
venue2.Save();
var chairs = DB.Find<Venue, object>()
.Match(v => v.Name == "Venue 1")
.Project(v => new { ChairCount = v.Properties["Chairs"] })
.Execute();
var avgChairs = DB.Collection<Venue>()
.Average(v => (int)v.Properties["Chairs"]);
}
}
}
results in the following queries being made to the database:
getting chairs in venue 1:
db.runCommand({
"find": "Venues",
"filter": {
"Name": "Venue 1"
},
"projection": {
"Properties.Chairs": NumberInt("1"),
"_id": NumberInt("0")
},
"$db": "test"
})
getting average chair count across all venues:
db.Venues.aggregate([
{
"$group": {
"_id": NumberInt("1"),
"__result": {
"$avg": "$Properties.Chairs"
}
}
}
])

MongoDB ,Delete arrays c#

I have this model
{ "_id" : 133,
"name" : "Gisela Levin",
"scores" : [ { "type" : "exam", "score" : 15.88727528055548 },
{ "type" : "quiz", "score" : 91.49884857295594 },
{ "type" : "homework", "score" : 16.56032169309347 },
{ "type" : "homework", "score" : 1.704262924559419 } ] }
i want to delete the less homework like this
{ "_id" : 133,
"name" : "Gisela Levin",
"scores" : [ { "type" : "exam", "score" : 15.88727528055548 },
{ "type" : "quiz", "score" : 91.49884857295594 },
{ "type" : "homework", "score" : 16.56032169309347 } ] }
thats my class
class students2 {
public int id { get; set; }
public string name { get; set; }
public scorest[] scores { get; set; }
}
public class scorest
{
public string type { get; set; }
public double score { get; set; }
}
thats my idea
searching all arrays, and then delete the lowest,but only show me one array by student
var query = await col.Find(x => x.name == "Gisela Levin").Project(Builders<students2>.Projection.Include(x => x.name).ElemMatch(x => x.scores, y => y.type == "homework")).ToListAsync();
If you mean you have read the data into your c# variables, and want to filter the data you could use linq in the following way;
public static students2 FilterStudentScores()
{
var student = new students2
{
id = 133,
name = "Gisela Levin",
scores = new scorest[] { new scorest { type = "exam", score= 15.88727528055548 },
new scorest{ type= "quiz", score= 91.49884857295594 },
new scorest{ type= "homework", score= 16.56032169309347 },
new scorest{ type= "homework", score= 1.704262924559419 } }
};
double maxScore = student.scores.Where(s => s.type.Equals("homework")).Max(s => s.score);
scorest[] filteredscores = student.scores.Where(s => !s.type.Equals("homework") || (s.type.Equals("homework") && s.score == maxScore)).ToArray();
students2 filteredStudent = new students2
{
id = 133,
name = "Gisela Levin",
scores = filteredscores
};
return filteredStudent;
}

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