How to dynamically access objects in ftl? - templates

I have my data model stored in yaml as below
users:
- "u1"
- "u2"
u1:
name: "user1"
age: 25
u2:
name: "user2"
age: 26
I am trying to use the below template (ftl) to generate user records
[
<#list users as user>
{
"username": "${${user}.name}"
"userage": "${${user}.age}"
},
</#list>
]
my final output should look like:
[
{
"username": "user1",
"userage": "25"
},
{
"username": "user2",
"userage": "26"
}
]
How to achieve this? I am getting below error

The expression you are looking for is .vars[user].name (where [] does the lookup by a dynamic key, and .vars is a special variable to refer to all your top-level variables). Then you can put that whole thing into ${} where that's needed. You can also do <#assign userObj = .vars[user]>, and then later just write userObj.name, and userObj.age. (Though, regrading the name choices, I would use userId instead of user, and user instead of userObj.)
Last not least, the data-model should just be like this, if possible, and then everything is simpler, and less confusing:
users:
u1:
name: "user1"
age: 25
u2:
name: "user2"
age: 26
So then you can write something like users.u1.age. If the user ID is dynamic, and let's say it's in the userId variable, then you can write users[userId].age.

In FreeMarker Template Language (FTL), you can dynamically access objects in your data model using the square bracket notation, like this:
[
<#list users as user>
{
"username": "${user.name}"
"userage": "${user.age}"
},
</#list>
]
Here, the users list is accessed using users as the key in the data model. The user variable in the list directive holds each value of the list one at a time. To access the properties of the u1 and u2 objects, you use user.name and user.age.
This should produce the desired output:
[ {
"username": "user1",
"userage": "25" },
{ "username": "user2",
"userage": "26" }]

Related

How to Search Nested Array of Object in DynamoDB

I am new to dynamoDb, i would like to search nested array properties. For ex my table has sample data given below
[{
id: '123',
name: 'test',
subShops: [
{
shopId: '234',
shopName: 'New Shop'
},
{
shopId: '345',
shopName: 'New Shop 2'
}
]
},
{
id: '1234',
name: 'test2',
subShops: [
{
shopId: '2345',
shopName: 'New Shop 3'
},
{
shopId: '3456',
shopName: 'New Shop 4'
}
]
}
]
I want to search where name : ['test', 'test2', 'test3'] or subShops[].shopeName where ['New Shop', 'New Shop 2', ''New Shop 3].
I have existing code for only name : ['test', 'test2', 'test3']
const params: AWS.DynamoDB.DocumentClient.ScanInput = {
TableName: VENDOR_TABLE_INFO.Name,
ExpressionAttributeNames: { "#Id": "name" },
FilterExpression: `#Id in (${Object.keys(keyValues).toString()}) or contains (subShops, :category2)`,
ExpressionAttributeValues: {
...keyValues,
':category2': {
...keyValues
}
}
};
Please notice that DynamoDB (DDB) is mainly a hyperscale key-value serverless datastore with very limited query pattern and flexibility, you need to be ok with that to use it.
In each DDB table you can only define one hash key (pk), and up to 5 local secondary index (sort key) for querying. And you can have up to 20 Global Secondary Index (GSI)
In you example, you have hash key of "id", and then if you need to query by "name" only, you need to build a GSI with name as hash key, and included the needed fields in the projection. There is no way to query by "shopname" in sub shop array unless you "flaten" the JSON tree structure.
In short, if you want JSON tree level data query/manipulation and all of your data is JSON documents, i would suggest you to use Amazon DocumentDB which is MongoDB 4 compatible, or directly use MongoDB itself.

Django QuerySet: Format query result as custom dictionary

I am working on a RBAC system for my Django-React app. I have this certain object structure that I want to generate but I am not sure how to do so directly from Django's QuerySet API.
Currently, I have this query
permissions |= PermissionAssignment.objects.filter(role=role['role__id']).values(
'permission__object__id',
'permission__object__name',
'permission__operation__id',
'permission__operation__name'
)
which returns this object on my frontend:
permissions: [
{
permission__object__id: 1,
permission__object__name: 'Post',
permission__operation__id: 1,
permission__operation__name: 'Read'
},
{
permission__object__id: 1,
permission__object__name: 'Post',
permission__operation__id: 2,
permission__operation__name: 'Write'
},
{
permission__object__id: 2,
permission__object__name: 'Event',
permission__operation__id: 2,
permission__operation__name: 'Read'
},
]
I do not require the permission object to have that complex structure. I only need to take hold of the object name and the operations enabled to this object for the current user. So basically, I just need it to be structured as:
permissions:[
"Post": {
operations: ['Read', 'Write']
},
"Event": {
operations: ['Read']
}
]
I know I can manipulate the original result on my frontend to get what I want, but I don't see that is necessary when I can format the result on the server-side level right away, except that I am not sure how to do that in Django.
You might be able to use list comprehension to achieve the desired outcome.
# NOTE: we use prefetch_related to avoid extra queries every time we access the object
permissions_qs = PermissionAssignment.objects.filter(role=role['role__id']).prefetch_related('object', 'operation')
d = {}
[d.update({p.object.name: {'operations': [p.operation.name]}}) if p.object.name not in d else d[p.object.name]['operations'].append(p.operations.name) for p in permissions_qs]
I have figured out the solution for what I wanted... The structure of the JSON response is different from what I defined in my question above, but I guess it is so much better.
However, I am posting the code here because I am having second thoughts with my approach i.e. I am starting to think the query is very expensive... and maybe someone can help check whether it is fine overall, or a bad practice indeed.
Code:
roles = RoleAssignment.objects.none()
modules = RoleModule.objects.none()
module_objects = ModuleObject.objects.none()
objects = Object.objects.none()
permissions = PermissionAssignment.objects.none()
roles = RoleAssignment.objects.filter(user=user).values('role__id', 'role__name')
for role in roles:
modules |= RoleModule.objects.filter(role=role['role__id']).values(
'role__id',
'module__id',
'module__name',
'module__slug',
'module__fontawesome_icon'
)
permissions |= PermissionAssignment.objects.filter(role=role['role__id']).values(
'permission__object__id',
'permission__object__name',
'permission__operation__id',
'permission__operation__name'
)
for module in modules:
module_objects |= ModuleObject.objects.filter(module=module['module__id']).values(
'module__id',
'module__name',
'object__id',
'object__name',
'object__slug'
)
# format modules to include respective objects and permissions
# this logic is primarily designed so that sidebar links can be...
# ...generated seamlessly thru frontend
formatted_modules = [
{
"name": x['module__name'],
"slug": x['module__slug'],
"icon": x['module__fontawesome_icon'],
"objects": [
{
"name": y['object__name'],
"slug": y['object__slug'],
"operations": [z['permission__operation__name'] for z in permissions if z['permission__object__id']==y['object__id']]
}
for y in module_objects if x['module__id']==y['module__id']
]
}
for x in modules
]
Then send it as response:
return Response({
"modules": formatted_modules
})
The JSON equivalence:
{
modules: [
{
name: 'Web Content',
slug: 'web-content',
icon: 'fas fa-newspaper',
objects: [
{
name: 'Post',
slug: 'post',
operations: [
'Read',
'Write',
'Modify',
'Delete'
]
}
]
},
{
name: 'Bids and Awards',
slug: 'bids-and-awards',
icon: 'fas fa-project-diagram',
objects: [
{
name: 'SRBP Goods & Services',
slug: 'srbp-goods-services',
operations: [
'Read',
'Write',
'Modify',
'Delete'
]
},
{
name: 'SRBP Infrastructure',
slug: 'srbp-infrastructure',
operations: [
'Read',
'Write',
'Modify',
'Delete'
]
}
]
}
]
}
In my UI:

DynamoDB LIKE '%' (contains) search over an array of objects using a key from the object, NodeJS

I am trying to use a "LIKE" search on DynamoDB where I have an array of objects using nodejs.
Looking through the documentation and other related posts I have seen this can be done using the CONTAINS parameter.
My question is - Can I run a scan or query over all of my items in DynamoDB where a value in my object is LIKE "Test 2".
Here is my DynamoDB Table
This is how it looks as JSON:
{
"items": [
{
"description": "Test 1 Description",
"id": "86f550e3-3dee-4fea-84e9-30df174f27ea",
"image": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/86f550e3-3dee-4fea-84e9-30df174f27ea.jpg",
"live": 1,
"status": "new",
"title": "Test 1 Title"
},
{
"description": "Test 2 Description",
"id": "e17dbb45-63da-4567-941c-bb7e31476f6a",
"image": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/e17dbb45-63da-4567-941c-bb7e31476f6a.jpg",
"live": 1,
"status": "new",
"title": "Test 2 Title"
},
{
"description": "Test 3 Description",
"id": "14ad228f-0939-4ed4-aa7b-66ceef862301",
"image": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/14ad228f-0939-4ed4-aa7b-66ceef862301.jpg",
"live": 1,
"status": "new",
"title": "Test 3 Title"
}
],
"userId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
I am trying to perform a scan / query which will look over ALL users (every row) and look at ALL items and return ALL instances where description is LIKE "Test 2".
I have tried variations of scans as per the below:
{
"TableName": "my-table",
"ConsistentRead": false,
"ExpressionAttributeNames": {
"#items": "items",
},
"FilterExpression": "contains (#items, :itemVal)",
"ExpressionAttributeValues": {
":itemVal":
{
"M": {
"description": {
"S": "Test 2 Description"
},
"id": {
"S": "e17dbb45-63da-4567-941c-bb7e31476f6a"
},
"image": {
"S": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/e17dbb45-63da-4567-941c-bb7e31476f6a.jpg"
},
"live": {
"N": "1"
},
"status": {
"S": "new"
},
"title": {
"S": "Test 2 Title"
}
}
}
}
}
The above scan works but as you can see I am passing in the whole object as an ExpressionAttributeValues, what I want to do is just pass in the description for example something like the below (which doesnt work and returns no items found).
{
"TableName": "my-table",
"ConsistentRead": false,
"ExpressionAttributeNames": {
"#items": "items.description",
},
"FilterExpression": "contains (#items, :itemVal)",
"ExpressionAttributeValues": {
":itemVal":
{
"S": "Test 2"
}
}
}
Alternatively, would it be better to create a separate table where all the items are added and they are linked via the userId? I was always under the impression there should be one table per application but in this instance I think if I had all the item data at the top level, scanning it would be a lot safer and faster.
So with nearly 200 views since posting and no responses I have come up with a solution that does not immediately solve the initial problem (I honestly do not think it can be solved) but have come up with an alternative approach.
Firstly I do not want two tables as this seems overkill, and I do not want the aws costs associated with two tables.
This has lead me to restructure the primary keys with prefixes which I can search over using the "BEGINS_WITH" dynamodb selector query.
Users will be added as U_{USER_ID} and items will be added as I_{USER_ID}_{ITEM_ID}, this way I only have one table to manage and pay for and this allows me to run BEGINS_WITH "U_" to get a list of users or "I_" to get a list of items.
I will then flatten the item data as strings so I can run "contains" searches on any of the item data. This also allows me to run a "contains {USER_ID}" search on the primary keys for items so I can get a list of items for a particular user.
Hope this helps anyone who might come up against the same issue.

How can I get the attribute value based on sibling attribute value from a json response?

This is my response.
[
{
"id": 123,
"name": "text1"
},
{
"id": 456,
"name": "text2"
},
{
"id": 789,
"name": "text3"
}
]
I can just provide the name value and want to get back the id attribute. I am using rest assured. I can create a map and then get it accordingly but searching for solutions like jsonPath().get(id where name ="text2"). Just thinking if anything can be done like that.
You can use conditions like .find{it.name=='text2'}.id

Ember V1.0.0-pre.2: capitalization in handlebars templates

We are using Ember V1.0.0-pre.2 and our handlebars is as follows:
{{#each data.Product}}
<div>
{{Details.uid}} - {{Details.Name}}
</div>
{{/each}}
Our the 'data' bit is from this json:
{
"Product": [
{
"Details": {
"uid": "1",
"Name": "one"
}
},
{
"Details": {
"uid": "2",
"Name": "two"
}
},
{
"Details": {
"uid": "3",
"Name": "three"
}
},
{
"Details": {
"uid": "4",
"Name": "four"
}
},
{
"Details": {
"uid": "5",
"Name": "five"
}
}
]
}
This fails with the following warning:
WARNING: Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos
When I change Details.whatever to details.whatever the warning disappears.
Is this by design or can we get around it somehow? The data is returned from the server in a fixed format and we wouldn't want to use another interim model if we can avoid it.
Ember has a naming policy where "instances/attributes" always start with a lowercase letter whilst "classes" always start with an uppercase letter. I think that's probably where you are running into some issues, if possible you should be de-serialising your JSON into attributes starting with lowercase letters.
Relevant part pulled from the guides (http://emberjs.com/guides/object-model/classes-and-instances/):
By convention, properties or variables that hold classes are capitalized, while instances are not. So, for example, the variable Person would contain a class, while person would contain an instance (usually of the Person class). You should stick to these naming conventions in your Ember applications.
Naming convention apply also to model data, but if you can't change what is coming from your API you can get around this by defining a map on a per property basis, e.g.
App.Adapter.map('App.Product', {
details: {key: 'Details'},
name: {key: 'Name'},
fooBar: {key: 'FOO_BaR'}
...
});
see here for more reference on how to map your json to your models: https://github.com/emberjs/data/blob/master/packages/ember-data/lib/system/mixins/mappable.js
hope it helps