How to convert list to expandobject key in c#? - c#

I have a function in which i am getting data(array of objects) from db and then adding those objects of array one by one into a lit of type ExpandoObject
public async Task<List<ExpandoObject>> GetGroupWithMaxTickets(){
List<ExpandoObject> topGroupsWithMaxTickets = new List<ExpandoObject>();
dynamic ticketDetails = new ExpandoObject();
var pipeline_tickets = new BsonDocument[]{
new BsonDocument("$match",
new BsonDocument
{
{ "nsp", "/sbtjapan.com" },
{ "datetime",
new BsonDocument
{
{ "$gte", "2019-12-03T00:00:34.417Z" },
{ "$lte", "2019-12-03T24:00:34.417Z" }
} }
}),
new BsonDocument("$group",
new BsonDocument
{
{ "_id", "$group" },
{ "totalTIckets",
new BsonDocument("$sum", 1) }
}),
new BsonDocument("$project",
new BsonDocument
{
{ "_id", 0 },
{ "group", "$_id" },
{ "totalTIckets", 1 }
}),
new BsonDocument("$sort",
new BsonDocument("totalTIckets", -1)),
new BsonDocument("$limit", 5)
};
var collection = await DbService.tickets.AggregateAsync<RawBsonDocument>(pipeline_tickets, new AggregateOptions {UseCursor = true, BatchSize = 500});
await collection.MoveNextAsync();
if(collection.Current.ToList().Count > 0){
// ticketDetails = JsonConvert.DeserializeObject(collection.Current.ToJson());
// ticketDetails.group = collection.Current.ToList()[0]["group"];
// ticketDetails.totalTickets = collection.Current.ToList()[0]["totalTIckets"];
Parallel.ForEach(collection.Current.ToList(), (ticket) => {
Console.WriteLine("Ticket----"+ticket);
dynamic groupWithTickets = new ExpandoObject();
groupWithTickets = ticket;
topGroupsWithMaxTickets.Add(groupWithTickets);
});
}
return topGroupsWithMaxTickets;
}
But it throws an error like this
System.AggregateException: One or more errors occurred. (The best overloaded method match for 'System.Collections.Generic.List<System.Dynamic.ExpandoObject>.Add(System.Dynamic.ExpandoObject)' has some invalid arguments)
I want that my function must return array of objects of type List<ExpandoObject>
How can i do this in c#?

Since you have changed the question, following is the answer that should resolve your matters.
How to NOT work with ExpandoObjects
I tested this on my system and got it to reproduce the same results as you are getting. Following is the failed try:
dynamic employee = new ExpandoObject();
List<ExpandoObject> listOfEmployees = new List<ExpandoObject>();
employee = "someStrangeString";
listOfEmployees.Add(employee); // ERROR !!!!
and just as expected, i get the following error on Add.
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
HResult=0x80131500
Message=The best overloaded method match for 'System.Collections.Generic.List.Add(System.Dynamic.ExpandoObject)' has some invalid arguments
Source=
StackTrace:
Corrected way of ExpandoObject use
Following is the method that will take care of the issues with Adding it to the list.
Parallel.ForEach(collection.Current.ToList(), (ticket) =>
{
Console.WriteLine("Ticket----" + ticket);
dynamic groupWithTickets = new ExpandoObject();
groupWithTickets.users = ticket; //<---- Assign ticket to users element.
topGroupsWithMaxTickets.Add(groupWithTickets);
});
What was done to fix it?
When you are working with ExpandoObjects, you have to think of dictionary type of a deal. When you declare ExpandoObject, you have to dynamically assign the value to an element (that you define).
Example from MS site: shows the proper use of ExpandoObject
dynamic employee, manager;
employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
Hopefully this resolves your issue.

It should be like this;
dynamic ticketDetails = new ExpandoObject();
ticketDetails.user = collection;
string json = Newtonsoft.Json.JsonConvert.SerializeObject(ticketDetails);

You can simply do this:
dynamic ticketDetails = new ExpandoObject();
ticketDetails = Json(new users = JsonConvert.DeserializeObject(collection.Current.ToJson()));

For testing purposes, i used an array arr that holds one of the elements. If you need that array to be part of ExtendoObject with first element being users, you can create a Json object and set the array as value to the "users" element.
dynamic ticketDetails = new ExpandoObject();
JArray arr = new JArray();
arr.Add(#"[{""name"": ""Alex"", ""age"": 21}]");
JObject o = new JObject();
o["users"] = arr.ToString();
ticketDetails = o;
// output: { "users" : [{"name" : "Alex", "age" : 21}]}

Related

MongoDb - cursor option is required after upgrade of mongodb

Since we were forced to upgrade our mongo installation, we're receiving an error during some aggregation function calls:
MongoDB.Driver.MongoCommandException: "Command 'aggregate' failed: The
'cursor' option is required, except for aggregate with the explain
argument (response: { "ok" : 0.0, "errmsg" : "The 'cursor' option is
required, except for aggregate with the explain argument", "code" : 9,
"codeName" : "FailedToParse" })"
BsonArray arr = BsonSerializer.Deserialize<BsonArray>("[{ \"$match\" : { \"Param1\" : \"VAL\" } }, { \"$unwind\" : \"$Entries\" }, { \"$match\" : { \"PARAM\" : \"VALUE\" } }]");
var pipeline = arr.Select(x => x.AsBsonDocument).ToList();
// AggregateArgs aArgs = new AggregateArgs { Pipeline = bsonList };
var cursor = collection.Aggregate(pipeline).ResultDocuments;
I already figured out, that we have to manually add cursor configuration to the BsonDocument - but we weren't able to figure out, how the query should be configured.
Is there any work around for this exception (without changing drivers)?
give this a shot:
var cursor = collection.Aggregate<BsonDocument>(pipeline);
var results = cursor.ToList(); //just get a list of documents and be done with it
while (cursor.MoveNext()) // or iterate over cursor
{
foreach (var doc in cursor.Current.ToArray())
{
//access your documents here
}
}
You have extra brace in the end of query string
was finally able to fix it, by building the command by myself:
var cmd = new CommandDocument()
{
{"aggregate", "collection_name" },
{"pipeline", arr},
{"cursor", BsonDocument.Parse("{}") }
};
var res = db.RunCommand(cmd);
This is what worked in my situation (mongocshardriver v1.9.0-rc0, mongodb server 4.4.0); OutputMode = AggregateOutputMode.Cursor in the AggregateArgs.
public IEnumerable<BsonDocument> Run(MongoCollection<Item> items)
{
var priceRange = new BsonDocument(
"$subtract",
new BsonArray
{
"$Price",
new BsonDocument(
"$mod",
new BsonArray{"$Price", 100})
});
var grouping = new BsonDocument(
"$group",
new BsonDocument
{
{"_id", priceRange},
{"count", new BsonDocument("$sum", 1)}
});
var sort = new BsonDocument(
"$sort",
new BsonDocument("_id", 1)
);
var args = new AggregateArgs
{
Pipeline = new[] { grouping, sort },
OutputMode = AggregateOutputMode.Cursor,
};
return items.Aggregate(args);
}

How do I represent an "empty object" for MongoDB .NET Driver?

I am trying to retrieve index statistics using the MongoDB .NET Driver.
I have tried the following variations of my pipeline
var statsPipeline = new[] { new BsonDocument(new BsonElement("$indexStats", BsonNull.Value)) };
var statsPipeline = new[] { new BsonDocument { {"$indexStats", "" } } };
var statsPipeline = new[] { new BsonDocument { {"$indexStats", null } } };
var statsPipeline = new[] { new BsonDocument { {"$indexStats", BsonNull.Value } } };
var statsPipeline = new[] { new BsonDocument { {"$indexStats", "{ }"} } };
which is passed to the query
var stats = await db
.GetCollection<BsonDocument>("CollectionName")
.AggregateAsync<BsonDocument>(statsPipeline);
With the exception of the one containing null, which resulted in an ArgumentNullException, I have received the exception
MongoDB.Driver.MongoCommandException: Command aggregate failed: The $indexStats stage specification must be an empty object.
How do I change my query such that the $indexStats stage specification is indeed an empty object?
Ok, this one worked:
var statsPipeline = new[] { new BsonDocument(new BsonElement("$indexStats", new BsonDocument())) };

c# Json Deserialization expression

maybe someone know the solution. I can't deserialize expression.
Client side:
var expresion= (Expression<Func<Company, bool>>)(model => model.Id ==id);
var respond = new JObject();
respond .Add("Expression", JToken.FromObject(expresion));
Server side:
JsonSerializer serializer = new JsonSerializer();
serializer.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
T p = (T)serializer.Deserialize(new JTokenReader(jObject), typeof(T));
Exception:
{"Unable to find a constructor to use for type System.Linq.Expressions.Expression`1[System.Func`2[HostStorageModels.Company,System.Boolean]]. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'Expression.Type'."}
I think that it is explicitly telling you that there is no constructor to build the Expression. If you check Expression Constructor () in the MSDN documentation, you will see that it is protected. You could try to send the expression in other serializable format and re build it when you receive it at the other side.
https://github.com/6bee/Remote.Linq
var query = (Expression<Func<Person, bool>>)(model => model.FirstName == "test2");
var remoteExpression = query.ToRemoteLinqExpression();
var request = new Request<Person>
{
Items = new List<Person>()
{
new Person() { FirstName = "test", Id = 1 },
new Person() { FirstName = "test2", Id = 2 }
},
Expression = remoteExpression
};
var serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
string jsonString = JsonConvert.SerializeObject(request, serializerSettings);
var result = JsonConvert.DeserializeObject<Request<Person>>(jsonString, serializerSettings);
var expresion = result.Expression.ToLinqExpression<Person, bool>();
var filtered = request.Items.Where(expresion.Compile()).ToList();

Creating C# Objects Dynamically

Currently having an issue creating a reusable object that I will need to use in a JSON construct string function.
Currently I have the following to create the bulk of the JSON string:
var data = new
{
record = new
{
value1 = Row.value1,
value2 = Row.value2,
form_values = new Dictionary<string, string>()
}
};
data.record.form_values["833b"] = Row.value3.ToString();
data.record.form_values["98wq"] = BuildMultiSelectList(Row.value3.ToString());
public object BuildMultiSelectList(string datavalue)
{
var choicelist = new {
choice_values: [datavalue],
other_values: [],
};
return choicelist;
}
The top half all works fine, though the function BuildMultiSelectList is giving errors such as "choice_values" does not exist in the current context and datavalue does not exist in the current context.
Any insight on why this has gone a bit rouge will be appreciated.
May be you are just mixing colon : with =?
var choicelist = new {
choice_values = new string[] {datavalue},
other_values = new[] {},
};

C# dynamic ExpandoObject Array

please tell me, how do I get the json like this:
dynamic packet = new ExpandoObject();
packet.type = "somethink";
packet.user = 12345;
packet.nets[0].amout = 123;
packet.nets[0].lower = 0;
packet.nets[1].amout = 345;
packet.nets[1].lower = 1;
string input = Newtonsoft.Json.JsonConvert.SerializeObject(packet);
Its not workig, error:
An unhandled exception of type "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException" in System.Core.dll
For more information: "System.Dynamic.ExpandoObject" does not contain definitions of "nets"
Thanks.
It's the ExpandoObject who's a dynamic object. The rest of properties should be other ExpandoObject instances or regular objects, arrays, collections...
For example:
packet.nets = new[]
{
new { amount = 123, lower = 0 },
new { amount = 345, lower = 1 }
}
Or:
packet.nets = new[]
{
new Dictionary<string, int> { { "amount", 345 }, { "lower", 0 } },
new Dictionary<string, int> { { "amount", 123 }, { "lower", 1 } }
}
There're many other approaches, including the use of instances of concrete classes.
Firstly, you need create nets in packet object, like this:
packet.nets = new dynamic[2];
And initialize the objects in nets, if you want with `ExpandoObject too:
packet.nets[0] = new ExpandoObject();
packet.nets[1] = new ExpandoObject();
Then is done, complete code:
dynamic packet = new ExpandoObject();
packet.type = "somethink";
packet.user = 12345;
packet.nets = new dynamic[2];
packet.nets[0] = new ExpandoObject();
packet.nets[0].amout = 123;
packet.nets[0].lower = 0;
packet.nets[1] = new ExpandoObject();
packet.nets[1].amout = 345;
packet.nets[1].lower = 1;
string input = Newtonsoft.Json.JsonConvert.SerializeObject(packet);
You first need to declare nets. For example
packet.nets = new Dictionary<int, dynamic>();
Then you'll need to instantiate the instances of nets
packet.nets[0] = new {amount = 123, lower = 0};
The result being
dynamic packet = new ExpandoObject();
packet.type = "somethink";
packet.user = 12345;
packet.nets = new Dictionary<int, dynamic>();
packet.nets[0] = new { amount = 123, lower = 0 };
packet.nets[1] = new { amount = 345, lower = 1 };

Categories

Resources