How to select nested attribute in scan in DynamoDB? - c#

I realize this is answered in the documentation (basically, "use the dot syntax"), but I'm still missing something. I'm using the .NET SDK and need to be able to select just a few attributes from a scan, one of which is a boolean inside a Map attribute. Note that I'm not trying to filter the results. I want all of the items, but I only want some of the attributes returned to me.
var config = new ScanOperationConfig
{
AttributesToGet = new List<string> { "foo.bar" },
Select = SelectValues.SpecificAttributes
};
var search = Table.Scan(config);
var documents = await search.GetRemainingAsync();
This code gets me the items I expect, but it's missing the "foo.bar" attribute. I know I can select the entire foo object, but I'm trying to minimize the amount of data handed back. I don't want the other attributes inside the foo object.
The relevant attribute of the item has the following JSON format:
{
"foo": {
"bar": true
}
}
I checked spelling, case sensitivity, etc. to no avail. Any idea what's wrong?

Instead of using Table.Scan, use the AmazonDynamoDBClient and you get more options.
The Client's ScanAsync method takes a ScanRequest which has a ProjectionExpression string. This is not present on the ScanOperationConfig class and that was the source of confusion.
Use the ProjectionExpression like so:
var scanRequest = new ScanRequest(Table.TableName)
{
ProjectionExpression = "foo.bar"
};
According to the documentation on ProjectionExpression:
ProjectionExpression replaces the legacy AttributesToGet parameter.
I didn't realize AttributesToGet was legacy until finally looking at the client for a totally unrelated problem and happened to find my answer to this problem.

Related

Filter multiple Event Types on Pulumi AzureNative Event Grid Topic Subscription

I create Event Grid Topic Subscriptions to Service Bus Queues:
var args = new EventSubscriptionArgs
{
EventSubscriptionName = topic.SubscriptionName,
Scope = topic.Id,
Destination = new Pulumi.AzureNative.EventGrid.Inputs.ServiceBusQueueEventSubscriptionDestinationArgs
{
EndpointType = "ServiceBusQueue",
ResourceId = queue.Id
},
};
var sub=new EventSubscription(
topic.SubscriptionName,
args
);
This works fine. Now I want to add a filter to only allow specific Event Types. According to the documentation I can add Filters like those:
args.Filter=new Pulumi.AzureNative.EventGrid.Inputs.EventSubscriptionFilterArgs
{
SubjectBeginsWith="the_topic",
SubjectEndsWith="the_topic"
}
But this is just one Topic, obviously. I need to be able to add an array of filters.
I expect that this can be done by EnableAdvancedFilteringOnArrays and AdvancedFilters somehow. But those properties aren't described anywhere (or I just wasn't able to find that information)
according to the documentation, AdvancedFilters is of type List<object> and I did not find any information what kind of object is expected there to be able to add multiple filters.
Haven’t used Pulumi, but I would suggest looking into the MSFT docs for Advanced filters (link) together with the docs on the operator you want to use, in your case stringBeginsWith.
As you can see the filtering should be applied in a key-value manner together with the operator to be used.
The Pulumi docs were half helpful. They showed the object you need to use but forget to mention the class is in the Pulumi.AzureNative.EventGrid.Inputs namespace. Below is a code snippet for creating the Pulumi.AzureNative.EventGrid.EventSubscription object. The Azure docs list the different type of filters you can use.
Filter = new AzureNative.EventGrid.Inputs.EventSubscriptionFilterArgs
{
IncludedEventTypes = new[]
{
"Microsoft.Devices.DeviceTelemetry"
},
AdvancedFilters = new[]
{
new Pulumi.AzureNative.EventGrid.Inputs.StringInAdvancedFilterArgs
{
OperatorType = Pulumi.AzureNative.EventGrid.AdvancedFilterOperatorType.StringIn.ToString(),
Key= "data.MyProperty",
Values= new[] { "MyValue" }
}
}
},

Handling nonexistant JSON tokens in JSON.Net how to return default instead of throwin exception

I have a problem, under http://www.pathofexile.com/api/public-stash-tabs link there is a huge API that returns a JSON string. Many of fields in this JSON are optional, that means they only appear if there is value present.
So theoretical "Item1" can have "abyssJewel" property but
"item2" doesnt have to have "abyssJewel" property
When i try to query this JSON with JSON.Linq like this
AbyssJewel = (bool)item["abyssJewel"];
in the case of Item1 everything is good and it returns proper value
but in case of Item2 i get exception "InvalidOperationException, Cannot access child value on Newtonsoft.Json.Linq.JProperty"
I understand its because for Item2 no abyssJewel property in JSON exists so it throws exception.
My question is this, how can i handle it so that instead of throwing exception it would return a default or null value for this particular field?
I have tried playing with Activator but couldnt make anything working on my own. Any tips?
im instantiating it like this:
apiPages.Add(new Page
{
Next_Change_Id = (string)jsonObject["next_change_id"],
Stashes = jsonObject["stashes"].Select(stash => new Stash
{
AccountName = (string)stash["accountName"],
StashName = (string)stash["stash"],
StashType = (string)stash["stashType"],
Public = (bool)stash["public"],
LastCharacterName = (string)stash["lastCharacterName"],
UniqueId = (string)stash["id"],
Items = stash.Select(item => new Item
{
AbyssJewel = (bool)item["abyssJewel"],
...tl;dr...
Instead of casting directly you should try to use the TryParse() method from the Boolean class, if something goes wrong it must return false. See here
Hope it will fix your problem.

How to add example values for parameters in Swagger-UI built by Nancy.Swagger package?

I have used Nancy.Swagger package and MetadataModule to build a Swagger UI for my APIs (according to this link: https://github.com/yahehe/Nancy.Swagger/wiki/Nancy.Swagger-for-Nancy-v2).
I get the UI, but the problem is that I cannot add example values for the properties of the object, which is passed as a parameter in body.
I see, for example, this output:
Here, instead of the word "string", I would like to have a real example value. But I don't know how I can add example values in this approach, and I would appreciate any help.
Snippet from the API and the parameter (object of PRequest):
Post("/", async (x, ctx) =>
{
PRequest PostRequestModel;
try
{
postRequestModel = this.Bind<PRequest>();
}
Snippet from MetaDataModule:
Describe["Post"] = desc => desc.AsSwagger(
with => with.Operation(
op => op.OperationId("Post")
.Tag("User")
.Summary("Post a new User")
.Description("This creates a new user.")
.BodyParameter(bp => bp.Description("A PRequest object").Name("PRequest").Schema<PRequest>())
I know it has been absolutely ages since you opened this, but I figured I'd share anyways.
First you need a model, like so:
public class Model
{
public string ExampleString { get; set; }
}
You need to create an instance of this model filled with whatever examples you want.
var exampleModel = new Model() { ExampleString = "foobar" }
Then you can add it to the BodyParameter like so:
.BodyParameter(para => para.Name("Example").Schema(
new Schema() { Example = exampleModel }
).Build())
I just created a public static class to hold all my example objects, then I set them like Example = Examples.Example1. I think this is the most readable approach.
A couple problems exist with this approach that I haven't found a solution to (yet). One is that the Example object does not seem to respect whatever settings you're using for Json serialization. Also, I've been unable to get this working concurrently with the Model view, but the Model view was always mostly useless in my eyes anyway. I'll update this if I ever figure any of these issues out. :)

Accessing the properties of an IEnumerable

I'm using TweetInvi to grab a bunch of tweets that match a specified hashtag. I do this with the following:
var matchingTweets = Search.SearchTweets(hashtag);
This returns an IEnumerable (named ITweet, interface of Tweet), however I cannot create a List<> of Tweets, because Tweet is a static type.
I made, instead, a list of objects, using:
List<object> matches = matchingTweets.Cast<object>().ToList();
However, although each member of the matchingTweets IEnumerable has a number of properties, I cannot access them using:
long tweetID = matches[i].<property>;
Using matches[i].ToString() returns the tweet content, so how can I effectively cast the results in matchingTweets to a list, and subsequently access the properties of those list members? I would ideally like to avoid using dynamic.
In your example above you were trying to grab the ID from the tweet. ITweet implements ITweetIdentifier which contains the Id property. You can literally just access it by:
var matchingTweets = Search.SearchTweets(hashtag);
//Grab the first 5 tweets from the results.
var firstFiveTweets = matchingTweets.Take(5).ToList();
//if you only want the ids and not the entire object
var firstFiveTweetIds = matchingTweets.Take(5).Select(t => t.Id).ToList();
//Iterate through and do stuff
foreach (var tweet in matchingTweets)
{
//These are just examples of the properties accessible to you...
if(tweet.Favorited)
{
var text = tweet.FullText;
}
if(tweet.RetweetCount > 100)
{
//TODO: Handle popular tweets...
}
}
//Get item at specific index
matchingTweets.ElementAt(index);
I don't know exactly what you want to do with all the info, but since the SearchTweets returns a IEnumerable of ITweets you have access to anything an ITweet has defined.
I highly recommend looking through their wiki. It's pretty well organized and gives you clear examples of some basic tasks.
It makes sense you cannot access the properties. You cast it into object so you can only access the objects properties and methods (that like you said might have been overridden).
It should be fine to just access it like this:
List<ITweet> tweets = matchingTweets.Take(5).ToList();
What you can do is project it to a new object of yours:
var tweets = matchingTweets.Select(item => new {
property1 = item.property1,
property2 = item.property2
})
.Take(5).ToList();
Then you will be able to access what you need. Now, if you need to share this data outside the scope of that function create a DTO object and initialize it instead of the anonymous type.
Depending on the size of the project and amount of effort usually it is in any case a good practice to create a layer of DTO objects when you interact with an external service like this. Then if their models changed you can contain your changes only to the DTOs.
If all you want are the ids of the first 5 then:
var ids = matchingTweets.Take(5).Select(item => item.id).ToList();

Generate Dynamic Linq query using outerIt

I am using Microsoft's Dynamic Linq (System.Linq.Dynamic) library to generate some queries at run time. This has worked great for me, but for one specific scenario.
Simplified scenario - I am trying to query all claims which have some specific tags that the user has selected and whose Balance is greater than some number.
static void Main(string[] args)
{
var claims = new List<Claim>();
claims.Add(new Claim { Balance = 100, Tags = new List<string> { "Blah", "Blah Blah" } });
claims.Add(new Claim { Balance = 500, Tags = new List<string> { "Dummy Tag", "Dummy tag 1" } });
// tags to be searched for
var tags = new List<string> { "New", "Blah" };
var parameters = new List<object>();
parameters.Add(tags);
var query = claims.AsQueryable().Where("Tags.Any(#0.Contains(outerIt)) AND Balance > 100", parameters.ToArray());
}
public class Claim
{
public decimal? Balance { get; set; }
public List<string> Tags { get; set; }
}
This query throws an error:
An unhandled exception of type 'System.Linq.Dynamic.ParseException' occurred in System.Linq.Dynamic.dll
Additional information: No property or field 'Balance' exists in type 'String'
Dynamic linq parser seems to try to find the Balance property on the Tag and not on the Claim object.
I have tried to play around with outerIt, innerIt, It keywords in Dynamic Linq but none of it seems to work.
Changing the sequence works, but that's not an option for me, since in the real application the filters, operators and patterns will be dynamic (configured by end user).
Boxing the conditions in brackets (), also doesn't help.
Workaround - create a simple contains condition for every Tag selected e.g. Tags.Contains("New") OR Tags.Contains("Blah") etc.. But in the real application it results in a really complex / bad query for each condition and kills the performance.
I might be missing something or this could be a bug in the library.
I would really appreciate if someone could help me with this.
Found a/the bug in ParseAggregate... The pushing of it→outerIt and back doesn't work if there are multiple levels. The code supposes that the it and outerIt won't be changed by a third party before being reset (technically the code isn't reentrant). You can try with other variants of System.Linq.Dynamic (there are like two or three variants out of there). Probably some variants have already fixed it.
Or you can take the code from the linked site and recompile it inside your code (in the end the "original" System.Linq.Dynamic is a single cs file) and you can patch it like this:
Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
{
// Change starts here
var originalIt = it;
var originalOuterIt = outerIt;
// Change ends here
outerIt = it;
ParameterExpression innerIt = Expression.Parameter(elementType, elementType.Name);
it = innerIt;
Expression[] args = ParseArgumentList();
// Change starts here
it = originalIt;
outerIt = originalOuterIt;
// Change ends here
MethodBase signature;
if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)
I've already opened an Issue with the suggested bug fix in the github of the project.
This seems to be working correctly in my version: System.Linq.Dynamic.Core
See the test here:
https://github.com/StefH/System.Linq.Dynamic.Core/blob/master/test/System.Linq.Dynamic.Core.Tests/ComplexTests.cs#L19

Categories

Resources