Update/Delete a sub document in mongodb using C# driver - c#

I have 2 classes:
public class Vote
{
public string VoteId { get; set; }
public string Question { get; set; }
public List<VoteAnswer> AnswerList { get; set; }
}
And:
public class VoteOption
{
public string OptionId { get; set; }
public string OptionName { get; set; }
public double VoteCount { get; set; }
}
How can i update/delete a VoteOption in a Vote where VoteId = voteId and OptionId = optionId? Using C# driver.
First I get VoteOption by:
var v = col.FindOneAs<Vote>(Query.EQ("VoteID", voteId));
VoteOption vo = v.AnswerList.Find(x => x.OptionId == optionId);
End set some value to it:
vo.OptionName = "some option chose";
vo.VoteCount = 1000;
But i don't know what next step to update this vo to Vote parent.
And, if i want to delete this vo, show me that way!
Data in MongoDB like that:
{
"_id" : "460b3a7ff100",
"Question" : "this is question?",
"AnswerList" : [{
"OptionId" : "1",
"OptionName" : "Option 1",
"VoteCount" : 0.0
}, {
"OptionId" : "2",
"OptionName" : "Option 2",
"VoteCount" : 0.0
}, {
"OptionId" : "3",
"OptionName" : "Option 3",
"VoteCount" : 0.0
}
}]
}

To update subdocument you can use this:
var update = Update.Set("AnswerList.$.OptionName", "new").Set("AnswerList.$.VoteCount", 5);
collection.Update(Query.And(Query.EQ("_id", new BsonObjectId("50f3c313f216ff18c01d1eb0")), Query.EQ("AnswerList.OptionId", "1")), update);
profiler:
"query" : { "_id" : ObjectId("50f3c313f216ff18c01d1eb0"), "AnswerList.OptionId" : "1" },
"updateobj" : { "$set" : { "AnswerList.$.OptionName" : "new", "AnswerList.$.VoteCount" : 5 } }
And to remove:
var pull = Update<Vote>.Pull(x => x.AnswerList, builder => builder.EQ(q => q.OptionId, "2"));
collection.Update(Query.And(Query.EQ("_id", new BsonObjectId("50f3c313f216ff18c01d1eb0")), Query.EQ("AnswerList.OptionId", "2")), pull);
profiler:
"query" : { "_id" : ObjectId("50f3c313f216ff18c01d1eb0"), "AnswerList.OptionId" : "2" },
"updateobj" : { "$pull" : { "AnswerList" : { "OptionId" : "2" } } }
Another way is to update parent document with modified child collection.

// Example function for update like count add like user using c#
public PostModel LikeComment(LikeModel like)
{
PostModel post = new PostModel();
_client = new MongoClient();
_database = _client.GetDatabase("post");
var collection = _database.GetCollection<PostModel>("post");
var _filter = Builders<PostModel>.Filter.And(
Builders<PostModel>.Filter.Where(x => x.PostId == like.PostId),
Builders<PostModel>.Filter.Eq("Comments.CommentId", like.CommentId));
var _currentLike = collection.Find(Builders<PostModel>.Filter.Eq("PostId", like.PostId)).FirstOrDefault().Comments.Find(f => f.CommentId == like.CommentId).Like;
var update = Builders<PostModel>.Update.Set("Comments.$.Like", _currentLike + 1);
collection.FindOneAndUpdate(_filter, update);
var addUser = Builders<PostModel>.Update.Push("Comments.$.LikeUsers", like.UserId);
collection.FindOneAndUpdate(_filter, addUser);
var _findResult = collection.Find(_filter).FirstOrDefault();
return _findResult;
}

//Delete comment
public PostModel delcomment(int postId, int commentId)
{
_client = new MongoClient();
_database = _client.GetDatabase("post");
var collection = _database.GetCollection<PostModel>("post");
var filter = Builders<PostModel>.Filter.Eq("PostId", postId);
var update = Builders<PostModel>.Update.PullFilter("Comments",
Builders<Comments>.Filter.Eq("CommentId", commentId));
collection.FindOneAndUpdate(filter, update);
var _findResult = collection.Find(filter).FirstOrDefault();
return _findResult;
}

Late answer but this is how you do it without having strings. If you modify your properties code will not compile. First time using expression tries in production code! They are awesome!
Models:
class Phone
{
public string _id { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
// Contain multiple lines as subdocument
public List<Line> Lines { get; set; }
}
class Line
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
}
Code: this is how I create my update statements without depending on strings.
var update = new UpdateDocument<Phone>();
// set filter
update.SetFilter(x => x._id == "123456789");
update.AddValueToUpdate(p => p.Name, "New Name");
update.AddValueToUpdate(p => p.Lines[0].Name, "Line 1");
update.AddValueToUpdate(p => p.Lines[1].Name, "Line 2");
update.AddValueToUpdate(p => p.DateCreated, DateTime.UtcNow);
var updateQuery = update.Build();
This creates this! That is what you need to pass to mondo in order to do the update
{ "_id" : "123456789" },
{$set:
{"Name":"New Name","Lines.0.Name":"Line 1","Lines.1.Name":"Line 2","DateCreated":ISODate("2021-04-30T16:04:59.332Z")}
}
If you wish that code to work here are the helper classes:
using MongoDB.Bson;
using System.Linq.Expressions;
using MongoDB.Bson.Serialization;
class UpdateDocument<T>
{
/// <summary>
/// _id of document to update.
/// </summary>
private string _filter;
/// <summary>
/// Example:
/// FirstName, Antonio
/// Education.Elementary.Year, 2004
/// </summary>
private List<KeyValuePair<string, object>> _valuesToUpdate { get; set; } = new List<KeyValuePair<string, object>>();
public void SetFilter(Expression<Func<T, bool>> filterDefinition)
{
var documentSerializer = BsonSerializer.SerializerRegistry.GetSerializer<T>();
var where = Builders<T>.Filter.Where(filterDefinition).Render(documentSerializer, BsonSerializer.SerializerRegistry);
_filter = where.ToJson();
}
public void AddValueToUpdate(string name, object value)
{
_valuesToUpdate.Add(new KeyValuePair<string, object>(name, value));
}
public void AddValueToUpdate(Expression<Func<T, object>> name, object value)
{
var memberExpression = name.Body as MemberExpression;
if (memberExpression == null)
{
var unaryExpression = name.Body as UnaryExpression;
if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert)
memberExpression = unaryExpression.Operand as MemberExpression;
}
var result = memberExpression.ToString();
result = result.Substring(result.IndexOf('.') + 1);
if (result.Contains("get_Item"))
result = Regex.Replace(result, #"(?x) get_Item \( (\d+) \)", m => $"{m.Groups[1].Value}");
AddValueToUpdate(result, value);
}
public string Build()
{
if (_valuesToUpdate.Any() == false)
{
// nothing to update
return null;
}
/*
update({
_id: 7,
"comments._id": ObjectId("4da4e7d1590295d4eb81c0c7")
},{
$set: {"comments.$.type": abc}
}, false, true
);
*/
StringBuilder sb = new StringBuilder();
sb.Append(_filter);
sb.Append(',');
sb.Append("{");
{
sb.Append("$set:{");
foreach (var item in _valuesToUpdate)
{
sb.Append('"');
sb.Append(item.Key);
sb.Append('"');
sb.Append(':');
var value = BsonExtensionMethods.ToJson(item.Value);
sb.Append(value);
sb.Append(',');
}
// remove last comma
sb.Length--;
sb.Append('}');
}
sb.Append("}");
return sb.ToString();
}
}

Related

How do i insert Adds many objects to the the List In c# MongoDB.Driver

How do I insert Adds many objects to the List In c# MongoDB.Driver?
my c# Entity
/// <summary>LogTest</summary>
public class VisitLog
{
/// <summary>MongoDB特有的字段</summary>
[MongoDB.Bson.Serialization.Attributes.BsonElement("_id")]
[JsonConverter(typeof(ObjectIdConverter))]
public MongoDB.Bson.ObjectId MongoId { get; set; }
/// <summary>YMD datetime</summary>
public int Yymmdd { get; set; }
/// <summary>Visitor</summary>
public string Visitor { get; set; }
/// <summary>VisitInfos</summary>
public List<VisitInfo> VisitInfos { get; set; }
}
In the MongoDBCode Like the code
// 1
{
"_id": ObjectId("5f506eb02000a9b52d72a600"),
"Yymmdd": NumberInt("20200903"),
"Visitor": "360spider",
"VisitInfos": [ ]
}
i will add objects to the "VisitInfos": [ ]
How do I insert Adds many objects to the List In c# MongoDB.Driver?
Way 1: insert only one object. my test code is:
var filter = Builders<VisitLog>.Filter.Eq("_id", item.MongoId);
var update = Builders<VisitLog>.Update.Push("VisitInfos", new VisitInfo { Visitor = Visitor, Browser = "IE", Ip = "192.168.1.1", Createtime = DateTime.Now.ToUnixTimeLocalIslong() });
var result = BB.UpdateOne(filter, update);
The Way 2: i want to insert InsertManyAsync
var items = BB.Find(x => x.Yymmdd.Equals(Yymmdd) && x.Visitor.Equals(Visitor)).Project<VisitLog>(fields).ToList();
if (items.Count > 0)
{
var item = items[0];
var VisitInfos = new List<VisitInfo>();
for (int j = 0; j < 10000; j++)
{
VisitInfos.Add(new VisitInfo { Visitor = Visitor, Browser = "IE", Ip = "192.168.1.1", Createtime = DateTime.Now.ToUnixTimeLocalIslong() });
}
var filter = Builders<VisitLog>.Filter.Eq("_id", item.MongoId);
var update = Builders<VisitLog>.Update.Push("VisitInfos", VisitInfos);
var result = BB.UpdateOne(filter, update);
}
the way 2 is failed.
please help me.
this very much.....
On the Builders<Order>.Update there's a PushEach which accepts an IEnumerable. This is equivalent to doing:
{ $push: { scores: { $each: [ 90, 92, 85 ] } } }
https://docs.mongodb.com/manual/reference/operator/update/push/#append-multiple-values-to-an-array
For simplicity here's an example of an order and order items.
In MongoDB we'll have:
> db.orders.find()
{ "_id" : ObjectId("5f50aef4d7d9f967d0322932"), "Items" : [ ] }
Then we'll execute the following C# Code.
var client = new MongoClient();
var db = client.GetDatabase("test");
var items = db.GetCollection<Order>("orders");
var filter = Builders<Order>.Filter.Empty;
var update = Builders<Order>.Update.PushEach(x => x.Items, new[]
{
new OrderItem{Name = "Order 1", Price = 10.1M},
new OrderItem{Name = "Order 2", Price = 20.2M}
});
await items.UpdateOneAsync(filter, update);
public class Order
{
public ObjectId Id { get; set; }
public List<OrderItem> Items { get; set; }
= new List<OrderItem>();
}
public class OrderItem
{
public string Name { get; set; }
public decimal Price { get; set; }
}
Now if we take a look at our document in MongoDB we'll have the 2 items added to our array
db.orders.find().pretty()
{
"_id" : ObjectId("5f50aef4d7d9f967d0322932"),
"Items" : [
{
"Name" : "Order 1",
"Price" : "10.1"
},
{
"Name" : "Order 2",
"Price" : "20.2"
}
]
}

Mongodb C# driver update all subarray elements

I want to update a document and set a value to an array of subdocument.
Using the documentation I have to use the $[] operator.
Following this link it is now possible to do stuff like this :
db.coll.update({}, {$set: {“a.$[].b”: 2}})
Input: {a: [{b: 0}, {b: 1}]}
Output: {a: [{b: 2}, {b: 2}]}
For example this request will do the job in my case :
db.collection.update(
{ "History": { "$elemMatch": { "status": { "$ne": "PROCESSED" } } } },
{ "$set": { "History.$[].flag": false } },
{ "multi": true }
)
But I do not find the way to do the $[] operator in C# with the driver.
And the driver documentation does not contain the information.
Can someone please provide me a C# sample.
you can achieve it like this:
collection.UpdateMany(
x => x.History.Any(h => h.status != "PROCESSED"),
Builders<YourType>.Update.Set("History.$[].flag", false));
here's an alternative strongly-typed solution:
using MongoDB.Entities;
using MongoDB.Entities.Core;
using System.Linq;
namespace StackOverflow
{
public class Test : Entity
{
public Event[] History { get; set; }
}
public class Event
{
public bool flag { get; set; }
public string status { get; set; }
}
public class Program
{
private static void Main(string[] args)
{
new DB("test", "localhost");
(new[] {
new Test { History = new[]{
new Event { flag = true, status = "PROCESSED" } } },
new Test { History = new[]{
new Event { flag = true, status = "NOT-PROCESSED" },
new Event { flag = true, status = "NOT-PROCESSED" }
}}
}).Save();
var field = Prop.PosAll<Test>(t => t.History[0].flag);
DB.Update<Test>()
.Match(t => t.History.Any(h => h.status != "PROCESSED"))
.Modify(b => b.Set(field, false))
.Execute();
}
}
}
Let's suppose that you have an object called History:
public class History : MongoDocument
{
// here you have some other properties, and you have a list of objects
public Guid Guid { get; private set; }
public List<SOME_OBJECT> NAME_OF_THE_ARRAY { get; set; }
}
And SOME_OBJECT:
public class SOME_OBJECT
{
// here you have other properties
public bool Flag { get; set; }
public string Name { get; set; }
}
And you want to update all objects into NAME_OF_THE_ARRAY:
public async Task<bool> Update_NAME_OF_THE_ARRAY(string id)
{
var filter = Builders<History>.Filter.Eq("_id", ObjectId.Parse(id));
var update = Builders<History>.Update.Combine(
Builders<History>.Update.Set(x => x.NAME_OF_THE_ARRAY[-1].Name, "test")
Builders<History>.Update.Set(x => x.NAME_OF_THE_ARRAY[-1].Flag, false);
var result = await _historyCollection.UpdateOneAsync(filter, update);
return result.ModifiedCount > 0;
}

Conditionally Populate Class Field in LINQ To Entities

I have an EF class that looks like this:
public class Item
public string ItemId{ get; set; }
public string NormalDescription { get; set; }
public string LongDescription { get; set; }
public string ShortDescription { get; set; }
.. <snip>
In addition, I have a DTO that looks like this:
public class ItemDTO
public string Id { get; set; }
public string DisplayName { get; set; }
.. <snip>
Upon loading the data from the 'Item' class into the DTO, I need to conditionally set 'DisplayName' based on a configuration setting. In other words, I'm looking for something similar to:
return _repo.GetAsQueryable<Item>()
.Select(i=> new ItemDTO
{
Id = i.ItemId,
DisplayName = (setting == 1) ? i.NormalDescription :
(setting == 2) ? i.LongDescription :
(setting == 3) ? i.ShortDescription :
String.Empty
}
Of course, this results in some very inefficient SQL (using 'CASE' to evaluate each possible value) being sent to the database. This is a performance issue as there's a TON of description fields on the Item.
That being said, is there a way to select ONLY the field that's required to populate the 'DisplayName' value?
In other words, instead of a query filled with 'CASE WHEN' logic, I'd like to ONLY retrieve one of the Description values based on my application configuration setting.
You should create lambda Expression dynamically:
var typeOfItem = typeof(Item);
var argParam = Expression.Parameter(typeOfItem, "x");
var itemIdProperty = Expression.Property(argParam, "ItemId");
var properties = typeOfItem.GetProperties();
Expression descriptionProperty;
if (setting < properties.Count())
descriptionProperty = Expression.Property(argParam, properties[setting].Name);
else
descriptionProperty = Expression.Constant(string.Empty);
var ItemDTOType = typeof(ItemDTO);
var newInstance = Expression.MemberInit(
Expression.New(ItemDTOType),
new List<MemberBinding>()
{
Expression.Bind(ItemDTOType.GetMember("Id")[0], itemIdProperty),
Expression.Bind(ItemDTOType.GetMember("DisplayName")[0], descriptionProperty),
}
);
var lambda = Expression.Lambda<Func<Item, ItemDTO>>(newInstance, argParam);
return _repo.GetAsQueryable<Item>().Select(lambda);
Something like this?
var repo = _repo.GetAsQueryable<Item>();
if (setting == 1)
{
return repo.Select(i => new ItemDTO
{
Id = i.ItemId,
DisplayName = i.NormalDescription
});
}
if (setting == 2)
{
return repo.Select(i => new ItemDTO
{
Id = i.ItemId,
DisplayName = i.LongDescription
});
}
if (setting == 3)
{
return repo.Select(i => new ItemDTO
{
Id = i.ItemId,
DisplayName = i.ShortDescription
});
}
return repo.Select(i => new ItemDTO
{
Id = i.ItemId,
DisplayName = String.Empty
});
EDIT
You can create the expression dynamically as Slava Utesinov showed. If you do not want to build the whole expression, you can replace just the parts you want:
public class UniRebinder : ExpressionVisitor
{
readonly Func<Expression, Expression> replacement;
UniRebinder(Func<Expression, Expression> replacement)
{
this.replacement = replacement;
}
public static Expression Replace(Expression exp, Func<Expression, Expression> replacement)
{
return new UniRebinder(replacement).Visit(exp);
}
public override Expression Visit(Expression p)
{
return base.Visit(replacement(p));
}
}
Expression<Func<Item, ItemDTO>> ReplaceProperty(
int setting, Expression<Func<Item, ItemDTO>> value)
{
Func<MemberExpression, Expression> SettingSelector(int ss)
{
switch (ss)
{
case 1: return x => Expression.MakeMemberAccess(x.Expression, typeof(Item).GetProperty(nameof(Item.NormalDescription)));
case 2: return x => Expression.MakeMemberAccess(x.Expression, typeof(Item).GetProperty(nameof(Item.LongDescription)));
case 3: return x => Expression.MakeMemberAccess(x.Expression, typeof(Item).GetProperty(nameof(Item.ShortDescription)));
default: return x => Expression.Constant(String.Empty);
}
}
return (Expression<Func<Item, ItemDTO>>)UniRebinder.Replace(
value,
x =>
{
if (x is MemberExpression memberExpr
&& memberExpr.Member.Name == nameof(Item.NormalDescription))
{
return SettingSelector(setting)(memberExpr);
}
return x;
});
}
private void Test()
{
var repo = (new List<Item>() {
new Item() {
ItemId ="1",
LongDescription = "longd1",
NormalDescription = "normald1",
ShortDescription = "shortd1" },
new Item() {
ItemId ="2",
LongDescription = "longd2",
NormalDescription = "normald2",
ShortDescription = "shortd2" }
}).AsQueryable();
for (int selector = 1; selector < 5; ++selector)
{
var tst = repo.Select(ReplaceProperty(selector,
i => new ItemDTO
{
Id = i.ItemId,
DisplayName = i.NormalDescription
})).ToList();
Console.WriteLine(selector + ": " + string.Join(", ", tst.Select(x => x.DisplayName)));
//Output:
//1: normald1, normald2
//2: longd1, longd2
//3: shortd1, shortd2
//4: ,
}
}

How to get Class Metadata into JSON string

How to generate JSON of Class meta data.
for eg.
C# Classes
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public Description Description { get; set; }
}
public class Description
{
public string Content { get; set; }
public string ShortContent { get; set; }
}
JSON
[
{
"PropertyName" : "Id",
"Type" : "Int",
"IsPrimitive" : true
},
{
"PropertyName" : "Name",
"Type" : "string",
"IsPrimitive" : true
},
{
"PropertyName" : "IsActive",
"Type" : "bool",
"IsPrimitive" : true
},
{
"PropertyName" : "Description",
"Type" : "Description",
"IsPrimitive" : false
"Properties" : {
{
"PropertyName" : "Content",
"Type" : "string",
"IsPrimitive" : true
},
{
"PropertyName" : "ShortContent",
"Type" : "string",
"IsPrimitive" : true
}
}
},
]
If you define a class that will map your Json Model:
public class PropertyDescription
{
public string PropertyName { get; set; }
public string Type { get; set; }
public bool IsPrimitive { get; set; }
public IEnumerable<PropertyDescription> Properties { get; set; }
}
And then just create a function that read the properties of your object recursively:
public static List<PropertyDescription> ReadObject(Type type)
{
var propertyDescriptions = new List<PropertyDescription>();
foreach (var propertyInfo in type.GetProperties())
{
var propertyDescription = new PropertyDescription
{
PropertyName = propertyInfo.Name,
Type = propertyInfo.PropertyType.Name
};
if (!propertyDescription.IsPrimitive
// String is not a primitive type
&& propertyInfo.PropertyType != typeof (string))
{
propertyDescription.IsPrimitive = false;
propertyDescription.Properties = ReadObject(propertyInfo.PropertyType);
}
else
{
propertyDescription.IsPrimitive = true;
}
propertyDescriptions.Add(propertyDescription);
}
return propertyDescriptions;
}
You can use Json.Net to serialize the result of this function :
var result = ReadObject(typeof(Product));
var json = JsonConvert.SerializeObject(result);
EDIT: Linq solution based on #AmitKumarGhosh answer:
public static IEnumerable<object> ReadType(Type type)
{
return type.GetProperties().Select(a => new
{
PropertyName = a.Name,
Type = a.PropertyType.Name,
IsPrimitive = a.PropertyType.IsPrimitive && a.PropertyType != typeof (string),
Properties = (a.PropertyType.IsPrimitive && a.PropertyType != typeof(string)) ? null : ReadType(a.PropertyType)
}).ToList();
}
...
var result = ReadType(typeof(Product));
json = JsonConvert.SerializeObject(result);
One probable solution -
static void Main(string[] args)
{
var o = typeof(Product).GetProperties().Select(a =>
{
if (a.PropertyType != null && (a.PropertyType.IsPrimitive || a.PropertyType == typeof(string)))
{
return MapType(a);
}
else
{
dynamic p = null;
var t = MapType(a);
var props = a.PropertyType.GetProperties();
if (props != null)
{ p = new { t, Properties = props.Select(MapType).ToList() }; }
return new { p.t.PropertyName, p.t.Type, p.t.IsPrimitive, p.Properties };
}
}).ToList();
var jsonString = JsonConvert.SerializeObject(o);
}
static dynamic MapType(PropertyInfo a)
{
return new
{
PropertyName = a.Name,
Type = a.PropertyType.Name,
IsPrimitive = a.PropertyType != null && a.PropertyType.IsPrimitive
};
}
Try this, concept is get all elements from object to dictionary. Field name and value. For each property create additional elements (using Reflection) in dictionary like Type, IsPrimitive etc. You can use recursion for going throw properties and then serialize this dictionary to JSON.
An example here:
Appending to JSON object using JSON.net
An example of this:
var serialize = new Newtonsoft.Json.JsonSerializer();
var dict = GetDic(new Description());
serialize.Serialize(sr, dict);
And GetDcit implementation:
private List<Dictionary<string, string>> GetDic(object obj)
{
var result= new List<Dictionary<string, string>>();
foreach (var r in obj.GetType().GetProperties())
{
result.Add(new Dictionary<string, string>
{
["PropertyName"] = r.Name,
["Type"] = r.PropertyType.Name,
["IsPrimitive"] = r.GetType().IsPrimitive.ToString(),
});
}
return result;
}

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