How to iterate through JSON array from n1ql query? - c#

so I'm using couchbase queue to Enqueue my beacon information. I'm trying to use n1ql query for my get method and I'm having trouble getting all the information. I realized I'm only getting the first beacon entry because result.Rows returns one element, an array of BeaconInfoN1ql. I wanted to iterate through that array and add each to a list.
try {
var cluster = new Cluster(new ClientConfiguration());
using (var bucket = cluster.OpenBucket("BeaconInfoN1ql"))
{
string query = "SELECT * FROM `BeaconInfoN1ql`";
var queryRequest = new QueryRequest(query);
var result = bucket.Query<dynamic>(queryRequest);
foreach (var row in result.Rows)
{
int i = 0;
var beacon = new Beacon()
{
SerialNumber = row.BeaconInfoN1ql[i].serialNumber,
ReceivedDate = Convert.ToDateTime(row.BeaconInfoN1ql[i].receivedDate),
ReceiverId = row.BeaconInfoN1ql[i].receiverId,
Distance = Convert.ToDouble(row.BeaconInfoN1ql[i].distance),
Rssi = Convert.ToInt32(row.BeaconInfoN1ql[i].rssi),
NewDistance = Convert.ToDouble(row.BeaconInfoN1ql[i].newDistance),
DistanceTesting = Convert.ToDouble(row.BeaconInfoN1ql[i].distanceTesting),
};
i++;
_beaconsList.Add(beacon);
}
}
return _beaconsList;
my result.Rows looks like this
result.Rows=
{{
"BeaconInfoN1ql": [
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
]
}}
I'm not sure about how to make the second foreach/for loop to iterate through all the keys.

For iterating JSON, I like to use dynamics. Here's an example:
var result = new Result()
{
Rows = #"{
'BeaconInfoN1ql': [
{
'distance': 2.2705747109792007,
'distanceTesting': 22,
'newDistance': 22,
'receivedDate': '0001-01-01T00:00:00',
'receiverId': '42008780c4b9b329',
'rssi': -73,
'serialNumber': '888'
}
]
}" //other entries omitted for brevity
};
dynamic parsedRows = JsonConvert.DeserializeObject(result.Rows);
foreach (var entry in parsedRows.BeaconInfoN1ql)
Debug.Write(entry.distance);
NOTE: I got rid of the double curly braces from your output in my example.

Related

Getting Json object to individual items in c# using linq

var respnse1 = client.GetAsync(hostmi).Result;
string content1 = respnse1.Content.ReadAsStringAsync().Result;
JObject joResponse = JObject.Parse(content1);
JObject ojObject = (JObject)joResponse["usermachine"];
JArray array = (JArray)joResponse["pInterval"];
var pLNo= (from p in array select ["pLocationNumber"]).ToList();
var pLIny= (from p in array select p["pLocationInterval"]).ToList();
// The following is not working
Usermachine um = new Usermachine();
um.employeeid = (string) ojObject["usermachine"]["employeeid"];
um.employeename = (string)ojObject["usermachine"]["employeename"];
I am getting an error at the um.employeeid = … which is system null exception.
I tried to see the content of ojObject in the immediate window as follows:
? ojObject
{
"employeeid": "1123",
"employeename": "EMP 001 NAME",
"mMacID": "E0138",
"machinename": "FOS",
"iscleaning": 1,
"isperforming": 1,
"isverifying": 1,
"cSeqno": 1,
"cMacID": "E0138",
"cInterval": 112,
"cCleanOperationMaxTime": 300,
"cPerformOperationMaxTime": 600,
"oSequenceID": 6,
"oMacID": "E0138",
"oItemNumber": " ",
"oBatchNumber": " ",
"oPONumber": " ",
"oCompletedOperation": 0,
"oComplOperStartTime": 0,
"oCompOperEndndTime": 0,
"oOperationToContinue": 1
}
base: {
"employeeid": "1123",
"employeename": "EMP 001 NAME",
"mMacID": "E0138",
"machinename": "FOS",
"iscleaning": 1,
"isperforming": 1,
"isverifying": 1,
"cSeqno": 1,
"cMacID": "E0138",
"cInterval": 112,
"cCleanOperationMaxTime": 300,
"cPerformOperationMaxTime": 600,
"oSequenceID": 6,
"oMacID": "E0138",
"oItemNumber": " ",
"oBatchNumber": " ",
"oPONumber": " ",
"oCompletedOperation": 0,
"oComplOperStartTime": 0,
"oCompOperEndndTime": 0,
"oOperationToContinue": 1
}
Type: Object
My objective is to get the employeeid and employeename if possible using a select (linq) query else even the above approach is OK if it works.
Ok, I got it working using Linq. As reference pasting the code below
var respnse1 = client.GetAsync(hostmi).Result;
string content1 = respnse1.Content.ReadAsStringAsync().Result;
JObject joResponse = JObject.Parse(content1);
JObject ojObject = (JObject)joResponse["usermachine"];
JArray array = (JArray)joResponse["pInterval"];
The Json string is as follows :
{
"usermachine": {
"employeeid": "1123",
"employeename": "EMP 001 NAME"
},
"pInterval": [
{
"pMachineID": "E0138",
"pmachinetoLocationSequence": 1
},
{
"pMachineID": "E0138",
"pmachinetoLocationSequence": 2
},
{
"pMachineID": "E0138",
"pmachinetoLocationSequence": 3
}
]
}
(I tried my best in formatting and pasting. Hope it sticks, still learning!!)
You will find that there is an array (pInterval ) as in master / detail relationship tables.
Now to get the master data code as follows:
string employeeid = (string) ojObject.SelectToken("employeeid");
string employeename = (string) ojObject.SelectToken("employeename");
Now to get the details data as follows
var pmachinetoLocationSequence= (from p in arrayselect p["pmachinetoLocationSequence"]).ToList();
foreach (var item in pmachinetoLocationSequence)
{
Console.WriteLine(item.Value<string>().ToString());
}
Is there a way to get multiple fields in the above var pmachinetoLocationSequence line ?

How create the filters in Function Score Query with .NET NEST Client

In Elasticsearch Document describe about Function Score Query show code as below
GET /_search
{
"query": {
"function_score": {
"query": { "match_all": {} },
"boost": "5",
"functions": [
{
"filter": { "match": { "test": "bar" } },
"random_score": {},
"weight": 23
},
{
"filter": { "match": { "test": "cat" } },
"weight": 42
}
],
"max_boost": 42,
"score_mode": "max",
"boost_mode": "multiply",
"min_score" : 42
}
}
}
I write this query to object initializer syntax
var searchRequest = new SearchRequest<ProductType>
{
Query = new FunctionScoreQuery()
{
Query = new MatchAllQuery {},
Boost = 5,
Functions = new List<IScoreFunction>
{
Filters...?
},
MaxBoost = 42,
ScoreMode = FunctionScoreMode.Max,
BoostMode = FunctionBoostMode.Max,
MinScore = 42
}
};
How to build filters in Functions?
The IScoreFunction interface allow only ExponentialDecayFunction, GaussDateDecayFunction, LinearGeoDecayFunction, FieldValueFactorFunction, RandomScoreFunction, WeightFunction, ScriptScoreFunction
Functions is a collection of IScoreFunction. In the example JSON, the first function is a random score function, and the second, a weight function. The linked Query DSL example has examples of the different functions, and here's an example to match the JSON above
var client = new ElasticClient();
var searchRequest = new SearchRequest<ProductType>
{
Query = new FunctionScoreQuery()
{
Query = new MatchAllQuery { },
Boost = 5,
Functions = new List<IScoreFunction>
{
new RandomScoreFunction
{
Filter = new MatchQuery
{
Field = "test",
Query = "bar"
},
Weight = 23
},
new WeightFunction
{
Filter = new MatchQuery
{
Field = "test",
Query = "cat"
},
Weight = 42
}
},
MaxBoost = 42,
ScoreMode = FunctionScoreMode.Max,
BoostMode = FunctionBoostMode.Multiply,
MinScore = 42
}
};
var searchResponse = client.Search<ProductType>(searchRequest);

C# Nested Parallel.ForEach while inserting into SQL database

We have an object (XML or JSON) and we map it to a DTO successfully, it takes too long (5~7 minutes) to be inserted in our database, so we went through Parallel.ForEach, but eventually, we noticed that there are some data entered incorrectly, like the Category has all items with the same name, but other different properties are 100% correct, in other case, we noticed that all data are the same in one category, although, the provided JSON object doesn't have that.
I confess it is so fast, it takes less than a minute, but with wrong insertion, have a look below on the used code:
JSON
[
{
"CategoryId": 1,
"CategoryName": "Drinks",
"SortOrder": 1,
"Products": [
{
"ProductId": 100,
"ProductName": "Black Tea",
"SortOrder": 1,
"Price": 5,
"Choices": []
},
{
"ProductId": 101,
"ProductName": "Turkish Coffee",
"SortOrder": 2,
"Price": 7.5,
"Choices": []
},
{
"ProductId": 102,
"ProductName": "Green Tea",
"SortOrder": 3,
"Price": 6,
"Choices": []
},
{
"ProductId": 103,
"ProductName": "Café Latte Medium",
"SortOrder": 4,
"Price": 10,
"Choices": []
},
{
"ProductId": 104,
"ProductName": "Orange Juice",
"SortOrder": 5,
"Price": 11,
"Choices": []
},
{
"ProductId": 105,
"ProductName": "Mixed Berry Juice",
"SortOrder": 6,
"Price": 12.5,
"Choices": []
}
]
},
{
"CategoryId": 1,
"CategoryName": "Meals",
"SortOrder": 1,
"Products": [
{
"ProductId": 200,
"ProductName": "Breakfast Meal",
"SortOrder": 1,
"Price": 16,
"Choices": [
{
"ChoiceId": 3000,
"ChoiceName": "Strawberry Jam",
"SortOrder": 1,
"Price": 0
},
{
"ChoiceId": 3001,
"ChoiceName": "Apricot Jam",
"SortOrder": 2,
"Price": 0
},
{
"ChoiceId": 3002,
"ChoiceName": "Orange Jam",
"SortOrder": 3,
"Price": 0
},
{
"ChoiceId": 3003,
"ChoiceName": "Café Latte",
"SortOrder": 4,
"Price": 2
}
]
},
{
"ProductId": 201,
"ProductName": "Mixed Grill",
"SortOrder": 1,
"Price": 30,
"Choices": [
{
"ChoiceId": 3004,
"ChoiceName": "Moutabal",
"SortOrder": 1,
"Price": 0
},
{
"ChoiceId": 3005,
"ChoiceName": "Mineral Water",
"SortOrder": 2,
"Price": 0
},
{
"ChoiceId": 3006,
"ChoiceName": "French Fries",
"SortOrder": 2,
"Price": 0
},
{
"ChoiceId": 3007,
"ChoiceName": "Grilled Potatoes",
"SortOrder": 2,
"Price": 0
}
]
}
]
}
]
C# code
Parallel.ForEach(categories, (category) =>
{
var newCreatedCategoryId = 0;
using (var connection = new SqlConnection("CONNECTION_STRING_HERE"))
{
connection.Open();
using (var command = new SqlCommand("SP_INSERT_INTO_CATEGORIES", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#P1", category.CategoryName);
command.Parameters.AddWithValue("#P2", category.SortOrder);
newCreatedCategoryId = int.Parse(command.ExecuteScalar().ToString());
command.Dispose();
}
connection.Close();
}
if (newCreatedCategoryId > 0)
{
Parallel.ForEach(category.Products, (product) =>
{
using (var connection = new SqlConnection("CONNECTION_STRING_HERE"))
{
connection.Open();
using (var command = new SqlCommand("SP_INSERT_INTO_PRODUCTS", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#P1", product.ProductName);
command.Parameters.AddWithValue("#P2", product.Price);
command.Parameters.AddWithValue("#P3", product.SortOrder);
command.Parameters.AddWithValue("#P4", newCreatedCategoryId);
command.ExecuteNonQuery();
command.Dispose();
}
connection.Close();
}
});
}
});
I had a look here, but this is not our issue, we are already using SCOPE_IDENTITY() to get the last generated identity in the current scope of execution.
On the other hand, it is not allowed to use SqlBulkCopy to insert this amount of data even if with no TableLock.
Its the newCreatedCategoryId that is the problem, what is confusing me is why you are calling newCreatedCategoryId = int.Parse(command.ExecuteScalar().ToString()); again in the inner loop. i mean if its just an id of category it doesn't need to be incremented again.
Take a look at the below edit. You might also be better to just put the second Parallel.ForEach into a standard foreach i mean this is all working in parallel anyway. Lastly Parallel.ForEach is not really suited to IO tasks, the correct pattern is async and await. on saying that you could probably use an ActionBlock out of TPL Dataflow to take advantage of the best of both worlds. Take a look at the dataflow example in the this question i answered Downloading 1,000+ files fast?
Parallel.ForEach(categories, (category) =>
{
var newCreatedCategoryId = 0;
using (var connection = new SqlConnection("CONNECTION_STRING_HERE"))
{
connection.Open();
using (var command = new SqlCommand("SP_INSERT_INTO_CATEGORIES", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#P1", category.CategoryName);
command.Parameters.AddWithValue("#P2", category.SortOrder);
newCreatedCategoryId = int.Parse(command.ExecuteScalar().ToString());
command.Dispose();
}
connection.Close();
}
if (newCreatedCategoryId > 0)
{
foreach(product in category.Products)
{
using (var connection = new SqlConnection("CONNECTION_STRING_HERE"))
{
connection.Open();
using (var command = new SqlCommand("SP_INSERT_INTO_PRODUCTS", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#P1", product.ProductName);
command.Parameters.AddWithValue("#P2", product.Price);
command.Parameters.AddWithValue("#P3", product.SortOrder);
command.Parameters.AddWithValue("#P4", newCreatedCategoryId);
command.Dispose();
}
connection.Close();
}
}//);
}
});
The objects that you are looping over are not thread-safe. You could add a lock object however this would serialise the operation and defeat the purpose of the Parallel.Foreach. You need to change theParallel.ForEach to a standard ForEach loop.
Potential Pitfalls in Data and Task Parallelism
You change the newCreatedCategoryId inside the Parallel.ForEach, which may cause incorrect data, because the queries wont run in order.

Extract all values from data in JSON

I have a json response with multiple movie titles in "data". Is there a way to quickly extract them? I need an array with just movie titles.
{
"page": "2",
"per_page": 10,
"total": 13,
"total_pages": 2,
"data": [{
"Poster": "N/A",
"Title": "They Call Me Spiderman",
"Type": "movie",
"Year": 2016,
"imdbID": "tt5861236"
}, {
"Poster": "N/A",
"Title": "The Death of Spiderman",
"Type": "movie",
"Year": 2015,
"imdbID": "tt5921428"
}, {
"Poster": "https://images-na.ssl-images-amazon.com/images/M/MV5BZDlmMGQwYmItNTNmOS00OTNkLTkxNTYtNDM3ZWVlMWUyZDIzXkEyXkFqcGdeQXVyMTA5Mzk5Mw##._V1_SX300.jpg",
"Title": "Spiderman in Cannes",
"Type": "movie",
"Year": 2016,
"imdbID": "tt5978586"
}]
}
You can use:
newtonsoft.
C# System.dynamic.
C# ExpandoObject Class.
In this way:
dynamic content = JsonConvert.DeserializeObject<ExpandoObject>(data);
Something like this:
using System;
using System.Dynamic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
string data = #"{
'page': '2',
'per_page': 10,
'total': 13,
'total_pages': 2,
'data': [{
'Poster': 'N/A',
'Title': 'They Call Me Spiderman',
'Type': 'movie',
'Year': 2016,
'imdbID': 'tt5861236'
}, {
'Poster': 'N/A',
'Title': 'The Death of Spiderman',
'Type': 'movie',
'Year': 2015,
'imdbID': 'tt5921428'
}, {
'Poster': 'https://images-na.ssl-images-amazon.com/images/M/MV5BZDlmMGQwYmItNTNmOS00OTNkLTkxNTYtNDM3ZWVlMWUyZDIzXkEyXkFqcGdeQXVyMTA5Mzk5Mw##._V1_SX300.jpg',
'Title': 'Spiderman in Cannes',
'Type': 'movie',
'Year': 2016,
'imdbID': 'tt5978586'
}]
}";
dynamic content = JsonConvert.DeserializeObject<ExpandoObject>(data);
int i;
int len = content.data.Count;
string result = "";
string[] myArray;
for (i = 0; i < len; i++)
{
result += content.data[i].Title; // Extract the movie title.
result += ","; // Conact with commas.
}
result = result.Substring(0, result.Length - 1);
myArray = result.Split(','); // Array of string with the movie titles.
Console.WriteLine(myArray[0]);
}
}
See in action: .NET Fiddle.
var data = new Dictionary<string, string>();
data.Add("foo", "baa");
JavaScriptSerializer ser = new JavaScriptSerializer();
var JSONString = ser.Serialize(data); //JSON encoded
var JSONObj = ser.Deserialize<Dictionary<string, string>>(JSONString); //JSON decoded
Console.Write(JSONObj["foo"]); //prints: baa
using Newtonsoft.Json.Linq might do the simplest work for you.
using Newtonsoft.Json.Linq;
List<string> movieTitles = (JObject.Parse(json)["data"]).
Cast<JToken>().Select(x => x["Title"].ToString()).ToList();

Delete JSON Data inside Property based on ID in C#

I have a requirement to delete the data inside JSON file. I have tried so many way but it is not deleting the data. I have also tried this example.
Remove JSON objects from a large file
But in above example they are passing a jsonstring but I have a jobject type of data.
My JSON File is as following.
{
"id": 123,
"name": "Pankaj Kumar",
"address": {
"street": "El Camino Real",
"city": "San Jose",
"zipcode": 95014
},
"experiences": [
{
"companyid": 1,
"companyname": "abc1"
},
{
"companyid": 20,
"companyname": "Genpact Headstrong"
},
{
"companyid": 71,
"companyname": "new company"
},
{
"companyid": 77,
"companyname": "Mind Tree LTD"
},
{
"companyid": 89,
"companyname": "TCS"
},
{
"companyid": 22,
"companyname": "Hello World LTD"
}
],
"phoneNumber": 9988664422,
"role": "Developer"
}
I want to delete company based on companyid.
I have tried following code to delete based on company id.
private void DeleteCompany() {
var json = File.ReadAllText(jsonFile);
try {
var jObject = JObject.Parse(json);
JArray experiencesArrary = (JArray) jObject["experiences"];
Console.Write("Enter Company ID to Delete Company : ");
var companyId = Convert.ToInt32(Console.ReadLine());
if (companyId > 0) {
var companyName = string.Empty;
foreach(var company in experiencesArrary.Where(obj => obj["companyid"].Value < int > () == companyId)) {
companyName = Convert.ToString(company["companyname"]);
}
var companyToDeleted = "{ 'id': " + companyId + ", 'companyname': '" + companyName + "'}";
experiencesArrary.Remove(companyToDeleted);
jObject["experiences"] = experiencesArrary;
string output = Newtonsoft.Json.JsonConvert.SerializeObject(jObject, Newtonsoft.Json.Formatting.Indented);
File.WriteAllText(jsonFile, output);
} else {
Console.Write("Invalid Company ID, Try Again!");
UpdateCompany();
}
} catch (Exception) {
throw;
}
}
Please suggest or modify my code which delete the data.
There is no need for creating deleteObject like you are doing, you are very close to solution.You can simply find your object like this and remove.
var companyToDeleted = experiencesArrary.Where(obj => obj["companyid"].Value<int>() == companyId).ToList();
foreach (var item in companyToDeleted)
{
experiencesArrary.Remove(item);
}
Update
var companyToDeleted = experiencesArrary.FirstOrDefault(obj => obj["companyid"].Value<int>() == companyId);
experiencesArrary.Remove(companyToDeleted);

Categories

Resources