get one key from nested document - c#

i have a document like this one.
{ "_id": { "$oid" : "517e3fccc9c02d22c85f3a6f" },
"skillData": [ { "skillID": 3001,
"level": 1 }, { "skillID": 3002,
"level": 1 }, { "skillID": 1,
"level": 1 }, { "skillID": 2,
"level": 1 }, { "skillID": 3,
"level": 1 } ],
"username": "myID"}
what i want to do is get the skillID and store it on a variable for comparing to my own array
my code is like this
foreach (var item in rows)
{
var skillData = (BsonArray)item["skillData"];//this is the array of the document
Console.WriteLine(skillData);
int i=0;
while(i < 5)
{
for (int j = 0; j < skillData.Count; j++)
{
if (skillData[j] == equipTileArray[i])//this is where i want to compare
{
isSkillIDFound = true;
break;
}
}
i++;
}
}
but skillData[j] return me the whole document while I only want the skillID from the document. what should i do now?

From the looks of it your document item skillData is an array of sub-documents, each of which contains values for skillID and level. So you need to further parse those. I'm not overly familiar with mongodb, but my guess would be that you need to either try referencing skillData[j]["skillID"] instead of skillData[j] or interpret each of the elements of skillData as a new BsonDocument

It seems that the problem of mine is solved via using code like this
var skillIDs = skillData[j].AsBsonDocument.GetValue("skillID").ToString();
here is some example using some code i post here:
foreach (var item in rows)
{
var skillData = (BsonArray)item["skillData"];//this is the array of the document
Console.WriteLine(skillData);
int i=0;
while(i < 5)
{
for (int j = 0; j < skillData.Count; j++)
{
var skillIDs = skillData[j].AsBsonDocument.GetValue("skillID").ToString();
if (skillIDs == equipTileArray[i])
{
isSkillIDFound = true;
break;
}
}
i++;
}
}
Thats All.

Related

C#, Newtonsoft, need to get array items not already handled

I have a json array that looks like...
{
"equipment": [{
"date_of_examination": "2022-05-20T14:08:38.072965",
"defect_type": ["DN"],
"eqpt_ref": "AA1",
"eqpt_name": ["2 Leg Chain Sling"],
"eqpt_manufacturer": "Merc",
"eqpt_model": "edes",
"part_no": "A1",
"serial_no": "A1",
"year": "2019",
"swl": "32 tons",
"exam_type": ["6 Months"],
"date_of_last_examination": "2021-11-20T00:00:00",
"date_of_next_examination": "2022-11-20T00:00:00",
"defect": "sling is torn",
"action_required": "replace"
}, {
"date_of_examination": "2022-05-20T14:12:23.997004",
"eqpt_ref": "AA2",
"eqpt_name": ["Other - "],
"eqpt_name_other": "widget",
"eqpt_manufacturer": "merc",
"eqpt_model": "edes",
"part_no": "B1",
"serial_no": "B1",
"year": "2019",
"swl": "32 tons",
"exam_type": ["6 Months"]
}, {
"date_of_examination": "2022-05-20T14:13:24.795136",
"defect_type": ["DF"],
"eqpt_ref": "CC1",
"eqpt_name": ["Endless Round Sling (2.5m)"],
"eqpt_manufacturer": "merc",
"eqpt_model": "edes",
"part_no": "c1",
"serial_no": "c1",
"year": "2019",
"swl": "42 tons",
"exam_type": ["6 Months"],
"defect": "stitching is coming undone",
"danger_value": "6",
"danger_units": ["Weeks"],
"action_required": "needs to be stitched again"
}]
}
I am attempting to loop through the array and filter items as I need, to populate a table later.
The table has three parts.
First, is show all items with a defect_type of "DN". Second is to show all defect_type of "DF", and the last part is to show all the rest (in his case, the one with eqpt_name of AA2)
My original code is...
for (int j = 0; j <= 2; j++)
{
// Note, some table name parts won't have the "Filter..." aspect
// the string below will change depending on which loop we are in.
string[] tableNameParts = "TableStart:equipment:defectNow:Filter:defect_type=DN".Split(':');
string tableNameJson = tableNameParts[1].Replace("»", "");
var jsonRows = IncomingJson[tableNameJson];
if (tableNameParts.Count() > 3)
{
// We probably have a filter set.
if (tableNameParts[3].Replace("»", "").ToLower() == "filter" && tableNameParts.Count() > 4)
{
// These values are not set in stone. It is what values have been set in the JSON, and then matched.
// for example... TableStart:<subform name>:<differentiator>:Filter:<field name>=<field value>
string[] FilterParts = tableNameParts[4].Split('=');
// Get the filter field and value to filter by
if (FilterParts.Count() > 1)
{
string FilterField = FilterParts[0].Replace("»", "");
string FilterValue = FilterParts[1].Replace("»", "");
JArray filteredArray = new JArray();
if (jsonRows[0].GetType() == typeof(JObject))
{
//int loopCount = 0;
foreach (JObject arrayObject in jsonRows) // Each group can have a set of arrays. (each record has multiple sub records)
//for (int i = 0; i < jsonRows.Count(); i++)
{
//JObject arrayObject = jsonRows[i];
foreach (var objectItem in arrayObject)
{
string objectItemValue = string.Empty;
if (objectItem.Value.GetType() == typeof(JArray))
{
foreach (var item in objectItem.Value)
{
objectItemValue += item;
}
}
else
{
objectItemValue = (string)objectItem.Value;
}
if (objectItem.Key == FilterField && objectItemValue == FilterValue)
{
// We need to save the item.
filteredArray.Add(arrayObject);
testArray.Add(arrayObject);
//arrayObject["filtered"] = true;
//IncomingJson[tableNameJson][loopCount]["filtered"] = true;
}
}
//loopCount++;
}
}
else
{
foreach (JArray arrayGroup in jsonRows) // The array group (e.g. fault_record_subform)
{
// We are looking through the json array, to find any rows that match our filter key and filter value.
// We will then add that into our jsonRows
//int loopCount = 0;
foreach (JObject arrayObject in arrayGroup) // Each group can have a set of arrays. (each record has multiple sub records)
{
foreach (var objectItem in arrayObject)
{
string objectItemValue = string.Empty;
if (objectItem.Value.GetType() == typeof(JArray))
{
foreach (var item in objectItem.Value)
{
objectItemValue += item;
}
}
else
{
objectItemValue = (string)objectItem.Value;
}
if (objectItem.Key == FilterField && objectItemValue == FilterValue)
{
// We need to save the item.
filteredArray.Add(arrayObject);
testArray.Add(arrayObject);
//arrayObject["filtered"] = true;
//IncomingJson[tableNameJson][loopCount]["filtered"] = true;
}
}
}
//loopCount++;
}
}
//filteredArray.CopyTo(testArray, 0);
jsonRows = filteredArray; // limit the jsonRows to the filtered set (overwrite the jsonRows)
}
}
}
else
{
// This is not a filter set
JArray singleArray = new JArray();
foreach(var arraySet in jsonRows)
{
if (!testArray.Intersect(arraySet).Any())
{
if (arraySet.GetType() == typeof(JObject))
{
singleArray.Add(arraySet);
}
else
{
foreach (JObject arrayObject in arraySet)
{
singleArray.Add(arrayObject);
}
}
}
}
jsonRows = singleArray;
}
}
By the time it gets to the "this is not a filter set" (which should be the third iteration of the loop), I need to be able to ignore the other filtered items, but as you might see, I have attempted to mark an item as filtered (then filter out). I have also tried to add the filtered items to an alternative array and use that to filter out. All to no avail.
How do I make it so that the "this is not a filter set" rows can ignore the rows already filtered?
=========== EDIT ==============
After reviewing the link from dbc to the fiddler (I don't have an account on there, and don't know how to link to my changes), I have it running in the fiddler with the code below.
JObject json = JObject.Parse(GetJson());
string[] tableNames = {"TableStart:equipment:defectNow:Filter:defect_type=DN","TableStart:equipment:defectFuture:Filter:defect_type=DF","TableStart:equipment:defectNone"};
for (int j = 0; j <= 2; j++)
{
// Note, some table name parts won't have the "Filter..." aspect
// the string below will change depending on which loop we are in.
string[] tableNameParts = tableNames[j].Split(':');
string tableNameJson = tableNameParts[1].Replace("»", "");
var jsonRows = json[tableNameJson];
if (tableNameParts.Count() > 3)
{
// We probably have a filter set.
if (tableNameParts[3].Replace("»", "").ToLower() == "filter" && tableNameParts.Count() > 4)
{
// These values are not set in stone. It is what values have been set in the JSON, and then matched.
// for example... TableStart:<subform name>:<differentiator>:Filter:<field name>=<field value>
string[] FilterParts = tableNameParts[4].Split('=');
// Get the filter field and value to filter by
if (FilterParts.Count() > 1)
{
string FilterField = FilterParts[0].Replace("»", "");
string FilterValue = FilterParts[1].Replace("»", "");
JArray filteredArray = new JArray();
if (jsonRows[0].GetType() == typeof(JObject))
{
//int loopCount = 0;
foreach (JObject arrayObject in jsonRows) // Each group can have a set of arrays. (each record has multiple sub records)
//for (int i = 0; i < jsonRows.Count(); i++)
{
//JObject arrayObject = jsonRows[i];
foreach (var objectItem in arrayObject)
{
string objectItemValue = string.Empty;
if (objectItem.Value.GetType() == typeof(JArray))
{
foreach (var item in objectItem.Value)
{
objectItemValue += item;
}
}
else
{
objectItemValue = (string)objectItem.Value;
}
if (objectItem.Key == FilterField && objectItemValue == FilterValue)
{
// We need to save the item.
filteredArray.Add(arrayObject);
//testArray.Add(arrayObject);
//arrayObject["filtered"] = true;
//IncomingJson[tableNameJson][loopCount]["filtered"] = true;
}
}
//loopCount++;
}
}
else
{
foreach (JArray arrayGroup in jsonRows) // The array group (e.g. fault_record_subform)
{
// We are looking through the json array, to find any rows that match our filter key and filter value.
// We will then add that into our jsonRows
//int loopCount = 0;
foreach (JObject arrayObject in arrayGroup) // Each group can have a set of arrays. (each record has multiple sub records)
{
foreach (var objectItem in arrayObject)
{
string objectItemValue = string.Empty;
if (objectItem.Value.GetType() == typeof(JArray))
{
foreach (var item in objectItem.Value)
{
objectItemValue += item;
}
}
else
{
objectItemValue = (string)objectItem.Value;
}
if (objectItem.Key == FilterField && objectItemValue == FilterValue)
{
// We need to save the item.
filteredArray.Add(arrayObject);
//testArray.Add(arrayObject);
//arrayObject["filtered"] = true;
//IncomingJson[tableNameJson][loopCount]["filtered"] = true;
}
}
}
//loopCount++;
}
}
//filteredArray.CopyTo(testArray, 0);
jsonRows = filteredArray; // limit the jsonRows to the filtered set (overwrite the jsonRows)
}
}
}
else
{
// This is not a filter set
JArray singleArray = new JArray();
foreach(var arraySet in jsonRows)
{
//if (!testArray.Intersect(arraySet).Any())
{
if (arraySet.GetType() == typeof(JObject))
{
singleArray.Add(arraySet);
}
else
{
foreach (JObject arrayObject in arraySet)
{
singleArray.Add(arrayObject);
}
}
}
}
jsonRows = singleArray;
}
}
What I need ultimately (the jsonRows will be used elsewhere in my code within the loop) is that the third set will have items not found in the first 2 sets.
After a bit of further experimentation, using dotnetfiddle as introduced to me by #dbc (thank you), I have created a List and added each arrayObject into the list during the filtering stages.
I then during the unfiltered stage check if my arraySet is contained in the List, and if not, then add that item to the remaining jsonRows, thereby giving me the balance of the original list.
As can be seen here...
https://dotnetfiddle.net/ot35Z2

Generic hierarchical DataView class with dynamic levels of sort keys

When we create a DataView with sort on multiple columns, we are forced to specify values of all the columns when using FindRows.
Example, if I have:
dv1 = new DataView(tbl1, null, "Col1, Col2, Col3", DataViewRowState.CurrentRows);
I am forced to specify values for all 3 columns when using FindRows.
It is not possible to retrieve all rows for a particular value of Col1 and "any" value for Col2 and Col3.
This is possible in a SortedList where I can have nested SortedList. So, the top level SortedList will have key as Col1, and value as another SortedList. The 2nd level SortedList will have key as Col2, and value as another SortedList. Finally, the 3rd level SortedList will have key as Col3, and the references to the DataRows.
Using such a SortedList, it is possible to write methods, like:
public DataRowView[] FindAny(object[] keys)
where if the keys array contains only 1 key, the code can find the 2nd level SortedList from the 1st level SortedList for the key, and then loop through the 2nd and 3rd level SortedList and return all rows, as they belong to 1st key.
My question is whether anyone has already written such a SortedList class which can take dynamic number of keys, and work with any DataTable / DataRow.
Note:
1. This question has nothing to do with presentation layer. I am looking for a helper class for data processing, say for analysing huge volume of data in multiple excel sheets.
2. I am not looking for a LINQ based solution currently. I will migrate to LINQ in future.
Thanks.
I managed to write my own generic class, which implements a hierarchial view of the data. Improvements in this are welcome.
public class HDataView
{
private SortedList mapDataRows;
int numMapLevels;
public HDataView(DataTable tbl, string[] colNames)
{
object colVal = null;
string colName = "";
SortedList currLvlMap = null, nextLvlMap = null;
DataRow dr1 = null;
ArrayList arlLastLvlData;
mapDataRows = new SortedList();
numMapLevels = colNames.Length;
for (int i = 0; i < tbl.Rows.Count; i++)
{
dr1 = tbl.Rows[i];
currLvlMap = mapDataRows;
for (int j = 0; j < colNames.Length; j++)
{
colName = colNames[j];
colVal = dr1[colName];
if (j == colNames.Length - 1)
{
arlLastLvlData = (ArrayList)currLvlMap[colVal];
if (arlLastLvlData == null)
{
arlLastLvlData = new ArrayList();
currLvlMap[colVal] = arlLastLvlData;
}
arlLastLvlData.Add(dr1);
}
else
{
nextLvlMap = (SortedList)currLvlMap[colVal];
if (nextLvlMap == null)
{
nextLvlMap = new SortedList();
currLvlMap[colVal] = nextLvlMap;
}
//For the next column, the current nextLvlMap will become the prevLvlMap
currLvlMap = nextLvlMap;
}
}
}
}
public ArrayList FindAnyRows(object[] keys)
{
object keyVal = "";
ArrayList arlDataRows = null, arlCurrRows = null;
SortedList startLvlMap = null, currLvlMap = null, nextLvlMap = null;
int mapLevel = 1, startLevel = 0;
currLvlMap = mapDataRows;
mapLevel = 1;
for (int i = 0; i < keys.Length; i++)
{
keyVal = keys[i];
if (currLvlMap == null)
{
break;
}
if (i == numMapLevels - 1)
{
arlDataRows = (ArrayList)currLvlMap[keyVal];
}
else
{
nextLvlMap = (SortedList)currLvlMap[keyVal];
currLvlMap = nextLvlMap;
mapLevel++;
}
}
if (arlDataRows == null)
{
arlDataRows = new ArrayList();
}
if (keys.Length > 0 && keys.Length < numMapLevels)
{
if (currLvlMap != null)
{
startLvlMap = currLvlMap;
startLevel = mapLevel;
if (mapLevel == numMapLevels)
{
for (int j = 0; j < startLvlMap.Count; j++)
{
arlCurrRows = (ArrayList)startLvlMap.GetByIndex(j);
if (arlCurrRows != null)
{
arlDataRows.AddRange(arlCurrRows);
}
}
}
else
{
for (int i = 0; i < startLvlMap.Count; i++)
{
mapLevel = startLevel;
currLvlMap = startLvlMap;
//travel full depth of this map, for each element of this map
for (; mapLevel <= numMapLevels; mapLevel++)
{
if (mapLevel == numMapLevels)
{
for (int j = 0; j < currLvlMap.Count; j++)
{
arlCurrRows = (ArrayList)currLvlMap.GetByIndex(j);
if (arlCurrRows != null)
{
arlDataRows.AddRange(arlCurrRows);
}
}
}
else
{
//Next level of current element of the starting map
nextLvlMap = (SortedList)currLvlMap.GetByIndex(i);
currLvlMap = nextLvlMap;
}
}
}
}
}
}
return arlDataRows;
}
}

how to populate a list dynamically within a dictionary in c#?

i want to populate a list in
dictionary.timeslot_events.Add(t, new List<int>() { i });
but it is giving me exception that more an item with the same key has already added.
i have also tried to populate list with add function timeslot_events.Add(t, new List<int>() { i }); but it is giving me exception that the given key was not present in the dictionary.
kindly guide how can i populate it successfully.? In C++, i used to do it with
map<int, vector<int>>
for (int i = 0; i < data.noevents; i++)
{
int t = (int)(rg.Next(1, 45));
Console.WriteLine(t);
timeslot_events.Add(t, new List<int>() { i });
}
Check if key is already present then add against that key else insert new KeyValue pair like below:
for (int i = 0; i < data.noevents; i++)
{
int t = (int)(rg.Next(1, 45));
Console.WriteLine(t);
if (timeslot_events.ContainsKey(t))
{
if (timeslot_events[t] == null)
{
timeslot_events[t] = new List<int>();
}
timeslot_events[t].Add(i);
}
else
{
timeslot_events.Add(t, new List<int>() { i });
}
}
I would use a bit of LINQ.
var query =
from n in Enumerable.Range(0, data.noevents)
group n by rg.Next(1, 45);
foreach (var x in query)
{
timeslot_events.Add(x.Key, x.ToList());
}

Fastest way to create json in C#

I have a sample of data which is given below.
{
"ditems": [
{
"type": "ditem",
"name": "webmet.com",
"ditem": 0,
"links": [
"www.abc.com/a",
"www.sempo.org/"
]
},
{
"type": "ditem",
"name": "webmet.com/who-we-are/careers",
"ditem": 2,
"links": [
"http://www.tele12.com/about",
"http://tele12.com/life-at-teletech-en-US/about-teletech/"
]
}
],
"themes": [
{
"type": "theme",
"name": "http://searchm.com/isr/agenda",
"description": "",
"slug": "http://searchm.com/isr/agenda-2"
},
{
"type": "theme",
"name": "http://www.sempo.org/",
"description": "",
"slug": "http://www.sempo.org/-2"
}
]
}
Here is my code
var InternalURLList = dtInternalURL.AsEnumerable().Select(c => c.Field<string>("URL")).Distinct().ToList();
StringBuilder sb = new StringBuilder();
StringBuilder ThemeSb = new StringBuilder();
sb.Append("{\"ditems\":[");
if (InternalURLList.Count > 0)
{
for (int i = 0; i < InternalURLList.Count; i++)
{
var ExternalDomainList = GetExternalDomain(Domain_ID, InternalURLList[i]).AsEnumerable().Select(c => c.Field<string>("ExternalDomain")).Distinct().ToList();
sb.Append("{\"type\":\"ditem\",");
sb.Append("\"name\":");
sb.Append("\"" + InternalURLList[i] + "\",");
sb.Append("\"ditem\":" + i + ",");
sb.Append("\"links\":[");
if (ExternalDomainList.Count > 0)
{
for (int j = 0; j < ExternalDomainList.Count; j++)
{
sb.Append("\"" + ExternalDomainList[j] + "\"");
sb.Append((j != ExternalDomainList.Count - 1) ? "," : "]") ;
}
}
else
{
sb.Append("]");
}
sb.Append("}");
sb.Append((i != InternalURLList.Count - 1)?",":"]");
}
}
else
{
sb.Append("]");
sb.Append(",");
}
DataTable dtDistinctDomain = GetDistinctExtDomain(Domain_ID);
var ExternalDomain = dtDistinctDomain.AsEnumerable().Select(c => c.Field<string>("ExternalDomain")).Distinct().ToList();
ThemeSb.Append(",\"themes\":[");
for (int i = 0; i < ExternalDomain.Count; i++)
{
// For theme
ThemeSb.Append("{\"type\":\"theme\",");
ThemeSb.Append("\"name\":\"" + ExternalDomain[i] + "\",");
ThemeSb.Append("\"description\":\"\",");
ThemeSb.Append("\"slug\":\"" + ExternalDomain[i] + "-2" + "\"}");
ThemeSb.Append((i != ExternalDomain.Count - 1)?",":"]");
}
ThemeSb.Append("}");
string ConceptMapTheme = ThemeSb.ToString() ;
string ConceptMapJSON = sb.ToString()+ThemeSb.ToString();
return ConceptMapJSON;
I am trying to make json in C# using StringBuilder. The for loop is taking too much time to generate the json. The table contains more than 2,00,000 records. How to create json in a fastest way using C#?
You can add the Newtonsoft.Json nuget package in your project.
Then you just need to call the serializer :
var jsonString = JsonConvert.SerializeObject(objectToSerialize);

How can I use an array from another class?

I am currently trying to use a string array populated with values from Class B in Class A.
I have tried to copy the array over as such
string[] playerHand2 = new string[5];
Array.Copy(Deck.playerHand, playerHand2, 5);
However I get a null reference exception when I try to display the contents like so:
Console.WriteLine("Players hand:");
foreach (var item in playerHand2)
{
Console.Write(item.ToString());
}
Any adive pointing me in the correct direction is much appreciated.
One of the items in Deck.playerHand was already null.
This null value is copied into playerHand2.
When itterating through playerHand2, null.ToString() is called, resulting in your NullReferenceException.
You can check for a null-value with:
bool hasNulls = Array.IndexOf(Deck.playerHand, null) > 0;
or with LINQ:
bool hasNulls = Deck.playerHand.Any(s => s == null);
You do not need to copy the Array to use it, and converting a string to string is not helpful.
You can simply use:
foreach (var item in Deck.playerHand)
{
Console.WriteLine(item);
}
in general, you can also overwrite null with " " using the following:
for(int x = 0; x < Deck.playerHand.Length; x++)
{
if(Deck.playerHand[x] == null)
{
Deck.playerHand[x] = " ";
}
}
combined that gives following code:
for(int x = 0; x < Deck.playerHand.Length; x++)
{
if(Deck.playerHand[x] == null)
{
Deck.playerHand[x] = " ";
}
Console.WriteLine(Deck.playerHand[x]);
}
or even more compact, see #saravanan:
foreach(string item in Deck.playerHand)
{
Console.Write(!string.IsNullOrEmpty(item)?item.ToString():"");
}
The following code works perfectly fine for me:
string[] playerHand = new string[7] { "1", "2", "3", "4", "5", "6", "7" };
string[] playerHand2 = new string[5];
Array.Copy(playerHand, playerHand2, 5);
Console.WriteLine("Players hand:");
foreach (var item in playerHand2)
{
Console.Write(item.ToString());
}
Did you actually fill your array 'playerHand' with valid data?
Else make sure you have no null-values in the array of 'playerHand', and the size of 'playerHand' must be at least as big as 'playerHand2'.
Else you can simply avoid this
foreach (var item in playerHand2)
{
if (string.IsNullOrEmpty(item)) { continue; }
Console.Write(item.ToString());
}

Categories

Resources