How to get single values from am gremlinquery in C# code - azure

I am using gremlin with Azure Cosmos DB. I'm using this code to get a list of files from a graph database.
public async Task<List<string>> GetFilesWithMoreThanOneFilename()
{
List<string> list = new List<string>();
using (var gremlinClient = new GremlinClient(gremlinServer, new GraphSON2Reader(), new GraphSON2Writer(), GremlinClient.GraphSON2MimeType))
{
var resultSet = await gremlinClient.SubmitAsync<dynamic>("g.V().hasLabel('file').where(out().count().is(gt(1)))");
if (resultSet.Count > 0)
{
foreach (var result in resultSet)
{
string output = JsonConvert.SerializeObject(result);
list.Add(output);
}
}
}
return list;
}
The output string looks like this:
{"id":"0a37e4896b6310b6d152f6cf89336173ffb89b819f7955494322e0f0bec017b4","label":"file","type":"vertex","properties":{"fileSize":[{"id":"456b087c-7cf3-43ea-a482-0f31219bc520","value":"41096"}],"mimeType":[{"id":"d849b065-16f8-465b-986c-f8e0fdda9ac7","value":"text/plain"}]}}
My Question is how I can get a single value from the result. For example just the ID or the mimeType or is the only possiblity to work with the output and string manipulation?

Due to your output data is in json format, so you could use Newtonsoft.Json to read the data.
I create a json file with your data, you could just parse the json data without file. And just read the id and properties.fileSize
static void Main(string[] args)
{
JObject jsonData = JObject.Parse(File.ReadAllText( "test.json"));
Console.WriteLine("id:"+jsonData["id"].ToString());
Console.WriteLine("properties:"+jsonData["properties"]["fileSize"].ToString());
Console.ReadLine();
}
And here is the result:
Hope this could help you, if yo ustill have other questions, please let me know.
Update: if you want to get the value in the array, you could use this to get the value:
Console.WriteLine("mimeType.value:" + jsonData["properties"]["mimeType"][0]["value"].ToString());

In general, you should only retrieve the values that you actually need and not vertices with all their properties and then filter locally. This is equivalent to relational databases where you wouldn't usually do SELECT * and instead do something like SELECT name.
Additionally, you should specify the return type you're expecting which allows Gremlin.NET to deserialize the result for you so you don't have to do that yourself.
These two suggestions together give you something like this:
var names = await client.SubmitAsync<string>(
"g.V().hasLabel('person').where(out().count().is(gt(1))).values('name')");
Console.WriteLine($"First name: {names.First()}");
names is then just a ResultSet<string> which implements IReadOnlyCollection<string>.

Related

preprocess csv files to convert key values to lowercase when using Hybris hotfolder

CSV files are having data in uppercase for keys like UID, is there a way to convert UID to lowercase and save when using hot folder in hybris. A change on our data source will take more time than hybris change.
I am thinking of creating a LowerCaseValueTranslator for impex. is it a good approach?
I have explored LowerCaseValueTranslator path.
#Override
public Object importValue(final String valueExpr, final Item toItem) throws JaloInvalidParameterException
{
clearStatus();
Double result = null;
if (!StringUtils.isBlank(valueExpr))
{
try
{
result = valueExpr.toLowerCase();
}
catch (final NumberFormatException exc)
{
setError();
}
}
return result;
}
}
I expect that it will work - is this the best approach to do this
Is the data/UID autogenerated by Hybris, or is it a custom value from user?
In any case, a translator is a good approach to do what you want (assuming the data is a custom value). If it is autogenerated by Hybris, I would keep it as-is.

access indexfields, batchfields and batch variables in custom module

In my setup form I configure some settings for my custom module. The settings are stored in the custom storage of the batch class. Given the variable IBatchClass batchClass I can access the data by executing
string data = batchClass.get_CustomStorageString("myKey");
and set the data by executing
batchClass.set_CustomStorageString("myKey", "myValue");
When the custom module gets executed I want to access this data from the storage. The value I get returned is the key for the batchfield collection or indexfield collection or batch variables collection. When creating Kofax Export Connector scripts I would have access to the ReleaseSetupData object holding these collections.
Is it possible to access these fields during runtime?
private string GetFieldValue(string fieldName)
{
string fieldValue = string.Empty;
try
{
IIndexFields indexFields = null; // access them
fieldValue = indexFields[fieldName].ToString();
}
catch (Exception e)
{
}
try
{
IBatchFields batchFields = null; // access them
fieldValue = batchFields[fieldName].ToString();
}
catch (Exception e)
{
}
try
{
dynamic batchVariables = null; // access them
fieldValue = batchVariables[fieldName].ToString();
}
catch (Exception e)
{
}
return fieldValue;
}
The format contains a string like
"{#Charge}; {Current Date} {Current Time}; Scan Operator: {Scan
Operator's User ID}; Page: x/y"
and each field wrapped by {...} represents a field from one of these 3 collections.
Kofax exposes a batch as an XML, and DBLite is basically a wrapper for said XML. The structure is explained in AcBatch.htm and AcDocs.htm (to be found under the CaptureSV directory). Here's the basic idea (just documents are shown):
AscentCaptureRuntime
Batch
Documents
Document
For a standard server installation, the file would be located here: \\servername\CaptureSV\AcBatch.htm. A single document has child elements itself such as index fields, and multiple properties such as Confidence, FormTypeName, and PDFGenerationFileName.
Here's how to extract the elements from the active batch (your IBatch instance) as well as accessing all batch fields:
var runtime = activeBatch.ExtractRuntimeACDataElement(0);
var batch = runtime.FindChildElementByName("Batch");
foreach (IACDataElement item in batch.FindChildElementByName("BatchFields").FindChildElementsByName("BatchField"))
{
}
The same is true for index fields. However, as those reside on document level, you would need to drill down to the Documents element first, and then retrieve all Document children. The following example accesses all index fields as well, storing them in a dictionary named IndexFields:
var documents = batch.FindChildElementByName("Documents").FindChildElementsByName("Document");
var indexFields = DocumendocumentstData.FindChildElementByName("IndexFields").FindChildElementsByName("IndexField");
foreach (IACDataElement indexField in indexFields)
{
IndexFields.Add(indexField["Name"], indexField["Value"]);
}
With regard to Batch Variables such as {Scan Operator's User ID}, I am not sure. Worst case scenario is to assign them as default values to index or batch fields.

SQLInjection against CosmosDB in an Azure function

I have implemented an Azure function that is triggered by a HttpRequest. A parameter called name is passed as part of the HttpRequest. In Integration section, I have used the following query to retrieve data from CosmosDB (as an input):
SELECT * FROM c.my_collection pm
WHERE
Contains(pm.first_name,{name})
As you see I am sending the 'name' without sanitizing it. Is there any SQLInjection concern here?
I searched and noticed that parameterization is available but that is not something I can do anything about here.
When the binding occurs (the data from the HTTP Trigger gets sent to the Cosmos DB Input bind), it is passed through a SQLParameterCollection that will handle sanitization.
Please view this article:
Parameterized SQL provides robust handling and escaping of user input, preventing accidental exposure of data through “SQL injection”
This will cover any attempt to inject SQL through the name property.
If you're using Microsoft.Azure.Cosmos instead of Microsoft.Azure.Documents:
public class MyContainerDbService : IMyContainerDbService
{
private Container _container;
public MyContainerDbService(CosmosClient dbClient)
{
this._container = dbClient.GetContainer("MyDatabaseId", "MyContainerId");
}
public async Task<IEnumerable<MyEntry>> GetMyEntriesAsync(string queryString, Dictionary<string, object> parameters)
{
if ((parameters?.Count ?? 0) < 1)
{
throw new ArgumentException("Parameters are required to prevent SQL injection.");
}
var queryDef = new QueryDefinition(queryString);
foreach(var parm in parameters)
{
queryDef.WithParameter(parm.Key, parm.Value);
}
var query = this._container.GetItemQueryIterator<MyEntry>(queryDef);
List<MyEntry> results = new List<MyEntry>();
while (query.HasMoreResults)
{
var response = await query.ReadNextAsync();
results.AddRange(response.ToList());
}
return results;
}
}

How to create complex types with Azure Stream Analytics queries

I try to transform flat JSON data from an Event Hub into a DocumentDB. The target structure should look like:
{
"id" : 1
"field_1" : "value_1",
"details" : {
"detail_field_1":"abc",
"detail_field_2":"def"
}
}
Created from source:
{
"id":1,
"field_1" : "value_1",
"detail_field_1":"abc",
"detail_field_2":"def"
}
I checked the documentation of Azure Stream Analytics but there ist no clear description how to create a proper Query.
Who one can help me?
You can leverage the new JavaScript UDF feature to write nested JSON objects to output.
Register a user-defined function, "UDF.getDetails()" as below:
function main(obj) {
//get details object from input payload
var details_obj = {};
details_obj.detail_field_1 = obj.detail_field_1;
details_obj.detail_field_2 = obj.detail_field_2;
return JSON.stringify(details_obj);
}
Then call the UDF in your query to get a string of the nested JSON object.
SELECT
id,
field_1,
UDF.getDetails(input) As details
INTO output
FROM input
Using JavaScript UDF feature, you can return complex JSON.
Example write function.
function main(obj) {
//get details object from input payload
var details_obj = {};
details_obj.detail_field_1 = obj.detail_field_1;
details_obj.detail_field_2 = obj.detail_field_2;
return details_obj;
}
You should not use JSON.stringify since it will make it a string instead of JSON object.
Use it like.
SELECT id, field_1, UDF.getDetails(input) As details
INTO output
FROM input

Linq queries and optionSet labels, missing formatted value

I'm doin a simple query linq to retrieve a label from an optionSet. Looks like the formatted value for the option set is missing. Someone knows why is not getting generated?
Best Regards
Sorry for the unclear post. I discovered the problem, and the reason of the missing key as formattedvalue.
The issue is with the way you retrieve the property. With this query:
var invoiceDetails = from d in xrmService.InvoiceSet
where d.InvoiceId.Value.Equals(invId)
select new
{
name = d.Name,
paymenttermscode = d.PaymentTermsCode
}
I was retrieving the correct int value for the option set, but what i needed was only the text. I changed the query this way:
var invoiceDetails = from d in xrmService.InvoiceSet
where d.InvoiceId.Value.Equals(invId)
select new
{
name = d.Name,
paymenttermscode = d.FormattedValues["paymenttermscode"]
}
In this case I had an error stating that the key was not present. After many attempts, i tried to pass both the key value and the option set text, and that attempt worked just fine.
var invoiceDetails = from d in xrmService.InvoiceSet
where d.InvoiceId.Value.Equals(invId)
select new
{
name = d.Name,
paymenttermscode = d.PaymentTermsCode,
paymenttermscodeValue = d.FormattedValues["paymenttermscode"]
}
My guess is that to retrieve the correct text associated to that option set, in that specific entity, you need to retrieve the int value too.
I hope this will be helpful.
Best Regards
You're question is rather confusing for a couple reasons. I'm going to assume that what you mean when you say you're trying to "retrieve a label from an OptionSet" is that you're attempting to get the Text Value of a particular OptionSetValue and you're not querying the OptionSetMetadata directly to retrieve the actual LocalizedLabels text value. I'm also assuming "formatted value for the option set is missing" is referring to the FormattedValues collection. If these assumptions are correct, I refer you to this: CRM 2011 - Retrieving FormattedValues from joined entity
The option set metadata has to be queried.
Here is an extension method that I wrote:
public static class OrganizationServiceHelper
{
public static string GetOptionSetLabel(this IOrganizationService service, string optionSetName, int optionSetValue)
{
RetrieveOptionSetRequest retrieve = new RetrieveOptionSetRequest
{
Name = optionSetName
};
try
{
RetrieveOptionSetResponse response = (RetrieveOptionSetResponse)service.Execute(retrieve);
OptionSetMetadata metaData = (OptionSetMetadata)response.OptionSetMetadata;
return metaData.Options
.Where(o => o.Value == optionSetValue)
.Select(o => o.Label.UserLocalizedLabel.Label)
.FirstOrDefault();
}
catch { }
return null;
}
}
RetrieveOptionSetRequest and RetrieveOptionSetResponse are on Microsoft.Xrm.Sdk.Messages.
Call it like this:
string label = service.GetOptionSetLabel("wim_continent", 102730000);
If you are going to be querying the same option set multiple times, I recommend that you write a method that returns the OptionSetMetadata instead of the label; then query the OptionSetMetadata locally. Calling the above extension method multiple times will result in the same query being executed over and over.

Resources