VTL: Add a new property to an maps inside an array (AWS Appsync, DynamoDB) - amazon-dynamodb

I'm new to VTL and AWS appsync and try to get my head around how things are working.
The maps that are representing Steps in a List should have the property id with a UUID before there are stored in DynamoDB. To accomplish this I tried to iterate over the array and access the put method on the map like in the example below.
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key": {
"id" : $util.dynamodb.toDynamoDBJson($util.autoId())
},
#set($input = $util.dynamodb.toMapValues($ctx.args.input))
#set($input.createdAt = $util.dynamodb.toDynamoDB($util.time.nowISO8601()))
#foreach($step in $input.steps)
$step.put('id', $util.dynamodb.toDynamoDBJson($util.autoId())))
#end
"attributeValues": $util.toJson($input)
}
my second try:
#foreach($step in $input.steps)
#set($step.id = $util.dynamodb.toDynamoDBJson($util.autoId()))
#end
but still, for no reason, my maps do not have the property id.
Is there maybe the problem what the foreach loop is giving me just a copy of the map I try to modify and not the original object?
Thank you for your time!
Hopefully, my question will serve all newbies to VTL and appsync

They do, it's just that the toMapValues utility method is returning you DynamoDB types.
So if "input.steps" is supposed to be a list what you're gonna get in there is an object like {"L": [ ... ]}
Try this:
#foreach($step in $input.steps.L)
$step.put('id', $util.dynamodb.toDynamoDBJson($util.autoId())))
#end

Related

How to filter objects based on the Symfony workflow's place which is an array?

I've been struggling with this for a while but can't find a clean way to do it, so I'm seeking for some help.
I have custom filters (ApiPlatform 2.5 and Symfony 5.1) on database API outputs, and I need to filter on the current workflow place, or status as you like, of each output.
The Status has the below structure, which is a symfony workflow's place :
Status = { "OPEN": 1 }
My issue is that the status is stored as an array in the DB, and I can't find a way to have the querybuilder finding a match.
I've tried to build locally an array to do an = , a LIKE or an IN :
$status['OPEN'] = 1;
$queryBuilder->andWhere(sprintf('%s.Status = :st', $rootAlias))
->leftJoin(sprintf('%s.Objs', $rootAlias), 'o')
->andWhere('o.Profile = :p')
->setParameters(array(
'st' => $status,
'p' => $profile
));
But no way :(
I implemented a workaround that works but I don't like it as I'm using workflows a lot and need a clean way to filter outputs.
My workaround is fairly simple, when the status is writen as an array in the DB, I also store it as a string in another field called StatusText, then filtering on StatusText is easy and straight.
Status can have different contents obviously : OPEN, CLOSING, CLOSED, ...
Help appreciated !!
Thanks
EDIT & Solution
As proposed by Youssef, use scienta/doctrine-json-functions and use JSON_EXTRACT :
composer require scienta/doctrine-json-functions
Important, that was part of my issue, use the Doctrine type json_array an not array to store the status or the state, however you call it, in the Database.
Integrate the alias provided inside the ApiPlatform custom filter :
$rootAlias = $queryBuilder->getRootAliases()[0];
$json_extract_string = "JSON_EXTRACT(".$rootAlias.".Status, '$.OPEN') = 1";
$queryBuilder->andwhere($json_extract_string )
->leftJoin(sprintf('%s.Objs', $rootAlias), 'o')
->andWhere('o.Profile = :p')
->setParameter('p', $profile);
You need to ask Doctrine if the JSON array contains the status, but you can't do that with the QueryBuilder method.
When you hit the ORM limitations you can use a Native Query with ResultSetMapping. It allows you to write a pure SQL query using specific features of your DBMS but still get entity objects.
Or you can use scienta/doctrine-json-functions and use JSON_EXTRACT

How to implement redux-search

I am trying to implement a search filter in my application which uses react/redux using redux-search. The first gotcha I get is when I try to add the store enhancer as in the example.
// Compose :reduxSearch with other store enhancers
const enhancer = compose(
applyMiddleware(...yourMiddleware),
reduxSearch({
// Configure redux-search by telling it which resources to index for searching
resourceIndexes: {
// In this example Books will be searchable by :title and :author
books: ['author', 'title']
},
// This selector is responsible for returning each collection of searchable resources
resourceSelector: (resourceName, state) => {
// In our example, all resources are stored in the state under a :resources Map
// For example "books" are stored under state.resources.books
return state.resources.get(resourceName)
}
})
)
I understand evarything up to the resourceSelector, when I tried to get a deep dive into the example to see how it works but I can barely see how they are generated and the last line returns an error, Cannot read property 'get' of undefined
My state object looks like this
state: {
//books is an array of objects...each object represents a book
books:[
//a book has these properties
{name, id, author, datePublished}
]
}
Any help from anyone who understands redux-search is helpful
If this line:
return state.resources.get(resourceName)
Is causing this error:
Cannot read property 'get' of undefined
That indicates that state.resources is not defined. And sure enough, your state doesn't define a resources attribute.
The examples were written with the idea in mind of using redux-search to index many types of resources, eg:
state: {
resources: {
books: [...],
authors: [...],
// etc
}
}
The solution to the issue you've reported would be to either:
A: Add an intermediary resources object (if you think you might want to index other things in the future and you like that organization).
B: Replace state.resources.get(resourceName) with state[resourceName] or similar.

Firebase .indexOn with complex DB structure

The current query you see below is not efficient because I have not setup the proper indexing. I get the suggestion Consider adding ".indexOn": "users/kxSWLGDxpYgNQNFd3Q5WdoC9XFk2" at /conversations in the console in Xcode. I have tried it an it works.
However, I need the user id after users/ to be dynamic. I've added a link to another post below that has tried a similar thing, but I just can't seem to get it. All help would be much appreciated!
Note: The console output user id above does not match the screenshot below, but does not matter to solve the problem I believe. Correct me if I'm wrong. Thanks!
Here is the structure of my DB in Firebase:
{
"conversationsMessagesID" : "-KS3Y9dMLXfs3FE4nlm7",
"date" : "2016-10-19 15:45:32 PDT",
"dateAsDouble" : 4.6601793282986E8,
"displayNames" : [ “Tester 1”, “Tester 2” ],
"hideForUsers" : [ "SjZLsTGckoc7ZsyGV3mmwc022J93" ],
"readByUsers" : [ "mcOK5wVZoZYlFZZICXWYr3H81az2", "SjZLsTGckoc7ZsyGV3mmwc022J93" ],
"users" : {
"SjZLsTGckoc7ZsyGV3mmwc022J93" : true,
"mcOK5wVZoZYlFZZICXWYr3H81az2" : true
}
}
and the Swift query:
FIRDatabase.database().reference().child("conversations")
.queryOrderedByChild("users/\(AppState.sharedInstance.uid!)").queryEqualToValue(true)
Links to other post:
How to write .indexOn for dynamic keys in firebase?
It seems fairly simple to add the requested index:
{
"rules": {
"users": {
".indexOn": ["kxSWLGDxpYgNQNFd3Q5WdoC9XFk2", "SjZLsTGckoc7ZsyGV3mmwc022J93", "mcOK5wVZoZYlFZZICXWYr3H81az2"]
}
}
}
More likely your concern is that it's not feasible to add these indexes manually, since you're generating the user IDs in your code.
Unfortunately there is no API to generate indexes.
Instead you'll need to model your data differently to allow the query that you want to do. In this case, you want to retrieve the conversations for a specific user. So you'll need to store the conversations for each specific user:
conversationsByUser {
"SjZLsTGckoc7ZsyGV3mmwc022J93": {
"-KS3Y9dMLXfs3FE4nlm7": true
},
"mcOK5wVZoZYlFZZICXWYr3H81az2": {
"-KS3Y9dMLXfs3FE4nlm7": true
}
}
It may at first seem inefficient to store this data multiple times, but it is very common when using NoSQL databases. And is really no different than if the database would auto-generate the indexes for you, except that you have to write the code to update the indexes yourself.

Mongo's elemMatch with meteor publish composite

I have a Mongo collection that looks similar to the below example, I am using meteor-publish-composite, https://atmospherejs.com/reywood/publish-composite to publish documents to the client. I know with Mongo I can do the following to return specific items within the authors array.
db.books.find({"authors.authorSlug": "author-1}, {authors: {$elemMatch: { authorSlug: "author-1"}});
When I try to achieve the same thing using meteor-publish-composite, this does not seem to work as it returns the entire the authors' array, my code is as below.
Books.find({"authors.authorSlug": slug}, {authors: {$elemMatch:{authorSlug: slug}}});
Is this even possible to achieve with publish-composite?
{
"title" : "Book1",
"authors" : [
{
"name" : "Author 1",
"authorSlug": "author-1"
},
{
"name" : "Author 2",
"slug" : "author-2"
},
],
"slug" : "book1"
}
You only use publish-composite when you are trying to join 2 or more related collections into a single reactive subscription. You simply need a standard publish/subscribe for your collection - and you say you have working code so I don't see what your problem is! Or are you trying to get at your books data in addition to other data around it?

How do you find the PHID of a Phabricator object?

I need to get the PHIDs for one project and several users in our Phabricator install. It seems like it should be trivial to find out how to do this, but I've searched the docs to no avail. Am I looking in the wrong place or something?
Easiest way:
Go to the project
Click New Task
Look at the URL, it will have a parameter like:
?projects=PHID-PROJ-owipizovyry4fatifwfd
PHID is "PHID-PROJ-owipizovyry4fatifwfd"
Option 2:
Go to your Conduit [phabricator_url]\conduit
Find the method project.query
Enter the name in a JSON encoded array (i.e. ["project name"])
Click Call Method
PHID will be one of the data elements:
{
"data" : {
"PHID-PROJ-oybqquyhhke4awiw2akz" : {
"id" : "19",
"phid" : "PHID-PROJ-oybqquyhhke4awiw2akz",
"name" : "project name",
"members" : [
"PHID-USER-gapak5h34h6d5yvl67dx",
"PHID-USER-674vq754zfuhyxgvvq7x",
"PHID-USER-qvcdsyc4oz7rzpzziiyk",
"PHID-USER-qmefzjtsrmnxjxpc45km",
"PHID-USER-pbhygge7rgpdowz3s5vk"
],
"slugs" : [
"project_name"
],
"dateCreated" : "1396666703",
"dateModified" : "1396668261"
}
}
}
A more robust method would be to call the conduit method phid.lookup:
https://<your install>/conduit/method/phid.lookup/
Then enter in names something like #user, #project or Z2 and you'll get the PHID.

Resources