I've tried different solutions but I'm not reaching anywhere.
I'm in a middle of a loop and sometimes I need to add data to an existing property (details in this case).
So, in the beginning I create the following JObject without any problem:
var json = JsonConvert.SerializeObject(
new {
details = new[]{
new{product_name = detail["product_name"].ToString(),
quantity = detail["quantity"].ToString(),
product_options = detail["product_options"].ToString()},
}
}
);
// _elements is an dictionary<int, JObject>
_elements.Add(id, JObject.Parse(json));
// output
{
"details": [
{
"product_name": "Oranges",
"quantity": "2",
"product_options": [],
}
]
}
But, for some reason, I need to add more products to the list of details, so I would like my output to be:
{
"details": [
{
"product_name": "Oranges",
"quantity": "2",
"product_options": [],
},
{
"product_name": "Coca Cola",
"quantity": "5",
"product_options": [],
}
]
}
I've tried so far without any success:
dic.Value.Property("details").Add(json);
dic.Value.SelectToken("details").Add(json);
Solved.
dic.Value["details"].Last.AddAfterSelf(JObject.Parse(json));
Related
I need to create a Dictionary that can used like this:
identityUrl = "https://...."
Dictionary<string, string> jsonDict;
var s = new FormUrlEncodedContent(jsonDict);
If I have JSON that looks like this, how do I create the jsonDict Dictionary so that it can be converted by FormUrlEncodedContent? The problem I am having is with the legs part of the JSON.
{
"time-in-force": "Day",
"order-type": "Limit",
"price": "2.0",
"price-effect": "Credit",
"legs": [
{
"instrument-type": "Equity Option",
"symbol": "SPY 191018C00298000",
"quantity": 1,
"action": "Buy to Open"
},
{
"instrument-type": "Equity Option",
"symbol": "SPY 191018C00295000",
"quantity": 1,
"action": "Sell to Open"
}
]
}
var response = await httpClient.PostAsync(identityUrl, s).ConfigureAwait(continueOnCapturedContext: false);
This post is similar, but not quite what I need.
There is an entity with custom fields that can change their value. The fields are stored as an array.
public class SomeEntity :...
{
...
public List<CustomField> FieldList { get; set; } = new List<CustomField>();
...
}
I use code like this to update one field:
var filterBuilder = Builders<SomeEntity>.Filter;
var updateFilter =
filterBuilder.Eq(e => e.EntityId, entityToUpdate.EntityId)
& filterBuilder.ElemMatch(e => e.FieldList, f => f.FieldId == updateField.FieldId);
var updateDef = Builders<SomeEntity>.Update.Set(e => e.FieldList[-1].Value, updateField.Value);
var updateRes = await GetEntityCollection().UpdateOneAsync(updateFilter, updateDef);
Sometimes it becomes necessary to update the values of several fields in the database at the same time, but I cannot find a way to do this in one action.
Is it possible in MongoDB to first search for a document using a filter, and then update/delete several elements of its array by their Id's (changes for each element may be different) in one action?
Is it possible to do the same for several documents (for example, remove fields with certain identifiers from all objects matching the filter)?
An example of an object before the change:
{
...
"fieldList": [
{
"id": "3bf2c235-82c3-40e4-91dc-46dc4c1ed177",
"type": 0,
"value": 10
},
{
"id": "5909dabd-fe8f-4edb-a642-c052e23082d8",
"type": 1,
"value": "some value"
},
{
"id": "66805403-d508-4b99-82f3-fa2ed828c19e",
"type": 3,
"value": "2019-08-01T12:00:00"
}
]
}
An example of an object after modification (only one document is updated):
{
...
"fieldList": [
{
"id": "3bf2c235-82c3-40e4-91dc-46dc4c1ed177",
"type": 0,
"value": 500
},
{
"id": "5909dabd-fe8f-4edb-a642-c052e23082d8",
"type": 1,
"value": "new value"
},
{
"id": "66805403-d508-4b99-82f3-fa2ed828c19e",
"type": 3,
"value": "2020-09-10T10:00:00"
}
]
}
An example of an object after a massive change (the document matched the filter, by analogy, all documents that would fit the filter should be updated - delete two fields, add a default value for some field):
{
...
"fieldList": [
{
"id": "3bf2c235-82c3-40e4-91dc-46dc4c1ed177",
"type": 0,
"value": 500,
"defaultValue": 150
}
]
}
starting from a JObject I can get the array that interests me:
JArray partial = (JArray)rssAlbumMetadata["tracks"]["items"];
First question: "partial" contains a lot of attributes I'm not interested on.
How can I get only what I need?
Second question: once succeeded in the first task I'll get a JArray of duplicated items. How can I get only the unique ones ?
The result should be something like
{
'composer': [
{
'id': '51523',
'name': 'Modest Mussorgsky'
},
{
'id': '228918',
'name': 'Sergey Prokofiev'
},
]
}
Let me start from something like:
[
{
"id": 32837732,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Of Thee I Sing: Overture (radio version)"
},
{
"id": 32837735,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Concerto in F : I. Allegro"
},
{
"id": 32837739,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Concerto in F : II. Adagio"
}
]
First question:
How can I get only what I need?
There is no magic, you need to read the whole JSON string and then query the object to find what you are looking for. It is not possible to read part of the JSON if that is what you need. You have not provided an example of what the data looks like so not possible to specify how to query.
Second question which I guess is: How to de-duplicate contents of an array of object?
Again, I do not have full view of your objects but this example should be able to show you - using Linq as you requested:
var items = new []{new {id=1, name="ali"}, new {id=2, name="ostad"}, new {id=1, name="ali"}};
var dedup = items.GroupBy(x=> x.id).Select(y => y.First()).ToList();
Console.WriteLine(dedup);
Suppose I have this simple object definition:
public class Item
{
public int section { get; set; }
public string item { get; set; }
}
I have some data in a single-depth array. This is JSON, which would be converted to C# objects via Json.NET:
[
{
"section": 0,
"item": "Hello!"
},
{
"section": 1,
"item": "First Steps"
},
{
"section": 1,
"item": "How to Ask for Help"
},
{
"section": 2,
"item": "Your First Program"
},
{
"section": 2,
"item": "The Code"
},
{
"section": 2,
"item": "How It Works"
},
{
"section": 3,
"item": "Where To Go From Here"
}
]
Using Entity Framework or some other method, I have arrived at a simple list of these objects as stated above, contained within a var variable.
Now what I want to do is get the same list, but where each section is grouped as an array within the outer array. For example, the JSON of what I want looks like this:
[
[
{
"section": 0,
"item": "Hello!"
}
],
[
{
"section": 1,
"item": "First Steps"
},
{
"section": 1,
"item": "How to Ask for Help"
}
],
[
{
"section": 2,
"item": "Your First Program"
},
{
"section": 2,
"item": "The Code"
},
{
"section": 2,
"item": "How It Works"
}
],
[
{
"section": 3,
"item": "Where To Go From Here"
}
]
]
My initial thought was to do something with a LINQ query using the groupby statement but I don't think this is what I'm looking for - groupby seems to be analogous to the SQL version so it can only be used for aggregate operations.
The only other option I have found so far is to use a LINQ query to get a list of all of the sections:
var allSections = (from x in myData select x.section).Distinct();
...and then iterate through those IDs and manually build the array:
List<List<Item>> mainList = new List<List<Item>>();
foreach (int thisSection in allSections.ToArray())
{
List<Item> thisSectionsItems = (from x in myData where x.section == thisSection select x).ToList();
mainList.Add(thisSectionsItems);
}
return mainList;
This should result in a proper enumerable that I can feed into JSON.NET and get the expected result, but this seems inefficient.
Is there a more LINQ-ish, or at least more efficient, way to split the items into groups?
You can certainly achieve this with .GroupBy()
var grouped = items
.GroupBy(x => x.section) // group by section
.Select(x => x.ToArray()) // build the inner arrays
.ToArray(); // return collection of arrays as an array
This is my JSON
{
"3659639": {
"EventID": 3659639,
"RaceNum": 2,
"Meeting": "Newton Abbot",
"RaceType": "T",
"Description": "Attheraces.Com Handicap Chase",
"Distance": "5300m",
"TrackCondition": "Good",
"Weather": "Overcast",
"Abandoned": 0,
"SuspendDateTime": "2014-06-17 00:00:42.0000000",
"OutcomeDateTime": "2014-06-17 00:00:00.0000000",
"EffectiveRaceDate": "2014-06-16",
"Status": "Paying",
"Results": [
{
"event_id": 3659639,
"saddle_number": 11,
"position": 1,
"status": "Final"
},
{
"event_id": 3659639,
"saddle_number": 16,
"position": 2,
"status": "Final"
},
{
"event_id": 3659639,
"saddle_number": 17,
"position": 3,
"status": "Final"
}
],
"Dividends": {
"0": {
"event_id": 3659639,
"source": "NSW",
"pool_type": "Duet",
"outcome": "11\/16",
"pool_value": 79.5,
"interim_dividend": 11.2,
"final_dividend": 11.2
},
"36": {
"event_id": 3659639,
"source": "VIC",
"pool_type": "Trifecta",
"outcome": "11\/16\/17",
"pool_value": 1733,
"interim_dividend": 2746.2,
"final_dividend": 2746.2
},
"37": {
"event_id": 3659639,
"source": "VIC",
"pool_type": "Win",
"outcome": "11",
"pool_value": 2541.06,
"interim_dividend": 25.5,
"final_dividend": 25.5
},
"RunnerProducts": {
"11": {
"TopeTotePlace": 12,
"MidTotePlace": 7.3,
"TopeToteWin": 29.8,
"MidToteWin": 28,
"BestOrSP": 29.8
},
"16": {
"TopeTotePlace": 2.3,
"MidTotePlace": 2
},
"17": {
"TopeTotePlace": 26.4,
"MidTotePlace": 24.2
}
}
}
},
"3622800": {
"EventID": 3622800,
"RaceNum": 2,
"Meeting": "Albion Park",
"RaceType": "H",
"Description": "Seymour Rising Stars Championship C0 Heat One",
"Distance": "1660m",
"TrackCondition": "Good",
"Weather": "Fine",
"Abandoned": 0,
"SuspendDateTime": "2014-06-17 15:09:10.0000000",
"OutcomeDateTime": "2014-06-17 15:08:00.0000000",
"EffectiveRaceDate": "2014-06-17",
"Status": "Closed",
"Results": [
],
"Dividends": {
"RunnerProducts": [
]
}
},
"3679673": {
"EventID": 3679673,
"RaceNum": 6,
"Meeting": "Thirsk",
"RaceType": "T",
"Description": "Market Cross Jewellers Handicap",
"Distance": "1200m",
"TrackCondition": null,
"Weather": null,
"Abandoned": 0,
"SuspendDateTime": "2014-06-18 02:20:00.0000000",
"OutcomeDateTime": "2014-06-18 02:20:00.0000000",
"EffectiveRaceDate": "2014-06-17",
"Status": "Open",
"Results": [
],
"Dividends": {
"RunnerProducts": [
]
}
}
}
I am trying to parse this using JSON.Net and i have tried this code.
var obj = JObject.Parse(json);
var query =
from JProperty ev in obj.AsJEnumerable()
from JProperty evid in ev.Value.AsJEnumerable()
let value = (JObject)evid.Value
select new
{
Description = (string)value["Description"]
};
I am getting this error "Unable to cast object of type 'Newtonsoft.Json.Linq.JValue' to type 'Newtonsoft.Json.Linq.JObject'."
i also want to read event_id which is inside results and dividents. Can anyone tell me what i am doing wrong here
Currently, you're getting the properties of the properties - and then trying to cast each of the values to JObject, and then taking the Description of that. That's one level too deep, as you have:
The root object
Each property of the root object, which genuinely has an object as its value
Each property of each of those values... most of which are just string properties, so the value can't be cast to JObject
It's not clear why you're using AsJEnumerable() at all, but all you need is the properties of the root object, which is easily obtained with the Properties() method. Likewise it's not clear why you're using an anonymous type, rather than just getting a sequence of strings. This works fine:
var query =
from ev in obj.Properties()
select (string) ev.Value["Description"];
Or without the query syntax:
var query = obj.Properties.Select(ev => (string) ev.Value["Description"]);
Next:
i also want to read event_id which is inside results and dividents
In the data you've given, that's always the same as the value of the EventID property in the top-level type. So you'd be better off with:
var query =
from ev in obj.Properties()
select new { Description = (string) ev.Value["Description"],
Id = (string) ev.Value["EventID"] };
If you really want to get at the values in the dividends and results, you'll need to work out how you'll handle the multiple entries in those properties.