I am trying to normalise my API data with normalizr.
Basically my RESTful API provides a /items resource with all CRUD operations and a /items/:item-id/pictures sub resource with CRUD operations as well.
GET /items returns something a deep nested response that needs normalization:
[
{
id: "item-id-1",
name: "Item One",
pictures: [
{
id: "picture-id-1",
mimeType: "image/png"
},
{
id: "picture-id-2",
mimeType: "image/jpeg"
}
]
},
{
id: "item-id-1",
name: "Item One",
pictures: []
}
]
Now for my question: Should I normalise the code with a reference of all picture ID on the item entity or a reference to the item on the picture entity?
Reference on the item:
{
items: {
"item-id-1": {
id: "item-id-1",
name: "Item One",
pictures: ["picture-id-1", "picture-id-2"]
}
...
},
pictures: {
"picture-id-1": {
id: "picture-id-1",
mimeType: "image/png"
},
"picture-id-2": {
id: "picture-id-2",
mimeType: "image/jpeg"
}
...
}
}
vs. reference on the picture:
{
items: {
"item-id-1": {
id: "item-id-1",
name: "Item One",
}
...
},
pictures: {
"picture-id-1": {
id: "picture-id-1",
itemId: "item-id-1"
mimeType: "image/png",
},
"picture-id-2": {
id: "picture-id-2",
itemId: "item-id-1"
mimeType: "image/jpeg"
}
...
}
}
My application will provide actions to delete and add single pictures to an item. With the reference on the item I feel like it is much more expensive if I just delete an image with DELETE /items/:item-id/pictures/:picture-id. Then I need to have an item reducer function that loops through every pictures array in the item store and update the state there as well as in the pictures store. But all the examples for redux and normalizr use this approach
The reference on the picture I think is much more straight forward but I do not know how to achieve that result with normalizr. (I could write it myself pretty easily tho)
Related
I have a list with the following data:
(List of halls, every hall has some events that start at a given time and end at a different time)
{
name: "hall 1"
events: [
{
name: "React lecture",
startAt: 1500225422,
endAt: 1500226422
}
]
}, {
name: "hall 2"
events: [
{
name: "Angular lecture",
startAt: 1500227422,
endAt: 1500228422
}
]
}
I would like to query all of the events, and their halls, to see what event is currently happens and where.
Given a current timestamp (lets say 1500225556), I would like to get:
{
name: "hall 1"
events: [
{
name: "React lecture",
startAt: 1500225422,
endAt: 1500226422
}
]
}
If necessary, I can flatten this a bit, and have a list of halls, and a list of events with a reference to the hall they take place at.
SQL equivalent (list):
WHERE startAt < 1500225556 AND endAt > 1500225556
I cannot think of a solution without a custom cloud function.
I have this Schema:
{
product: S // Primary Key, // my Hash
media: L // List of Maps
}
Each media item will be like this:
[
{
id: S, // for example: id: uuid()
type: S, // for example: "image"
url: S // for example: id: "http://domain.com/image.jpg"
}
]
Sample Data:
{
product: "IPhone 6+",
media: [
{
id: "1",
type: "image",
url: "http://www.apple.com/iphone-6-plus/a.jpg"
},
{
id: "2",
type: "image",
url: "http://www.apple.com/iphone-6-plus/b.jpg"
},
{
id: "3",
type: "video",
url: "http://www.apple.com/iphone-6-plus/overview.mp4"
}
]
}
I want to be able to remove from media list by id.
Something like: "From product: 'IPhone 6+', remove the media with id: '2'"
After the query, the Data should be like this:
{
product: "IPhone 6+",
media: [
{
id: "1",
type: "image",
url: "http://www.apple.com/iphone-6-plus/a.jpg"
},
{
id: "3",
type: "video",
url: "http://www.apple.com/iphone-6-plus/overview.mp4"
}
]
}
How should i express query like this? I saw a post on UpdateItem but i can't find a good example for this query type.
Thanks!
Unfortunately, the API doesn't have this feature. The closest you can do is to delete an entry from "List" data type if you know the index.
I understand that most of the time the index mayn't be available. However, you can take a look at this alternate option if you don't have any other solution.
You also need to understand that even though DynamoDB started supporting the Document data types such as List, Map and Set, you can't perform some actions. Some features are yet to be added in the API. I believe this scenario is one of them.
I have used REMOVE to delete the item from list.
var params = {
TableName : "Product",
Key : {
"product" : "IPhone 6+"
},
UpdateExpression : "REMOVE media[0]",
ReturnValues : "UPDATED_NEW"
};
console.log("Updating the item...");
docClient.update(params, function(err, data) {
if (err) {
console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("UpdateItem succeeded:", JSON.stringify(data));
}
});
This is just for your reference:-
The Delete operator can be used only on SET.
DELETE - Deletes an element from a set.
If a set of values is specified, then those values are subtracted from
the old set. For example, if the attribute value was the set [a,b,c]
and the DELETE action specifies [a,c], then the final attribute value
is [b]. Specifying an empty set is an error.
The DELETE action only supports set data types. In addition, DELETE
can only be used on top-level attributes, not nested attributes.
We are using a server based simple grid. The grid reads and updates data for a remote data source. It has two columns that are using drop down editors. Everything seems to work fine except that after saving, when editor closes, the changed values are not displayed in the edited row. It still shows the old value. When we try to refresh the grid using the sync event, it changes the order of the rows however, it does update the values on refresh.
It seems like the template function is not executed after the update is completed. How to edit the grid / code to ensure that the changed value is reflected in the grid?
Grid Definition code:
$("#servicetype-grid").kendoGrid({
pageable: true,
toolbar: [{name: "create", text: ""}, { template: kendo.template($("#servicetype-search-template").html())}],
columns: [
{
field: "serviceName", title: "Service Name"
},
{
field: "billCalculationTypeId",
editor: calculationTypeDropDownEditor,
template: function(dataItem) {
return kendo.htmlEncode(dataItem.billCalculationTypeName);
},
title: "Bill Calculation Type"
},
{
field: "payCalculationTypeId",
editor: calculationTypeDropDownEditor,
template: function(dataItem) {
return kendo.htmlEncode(dataItem.payCalculationTypeName);
},
title: "Pay Calculation Type"
},
{
command: [
{ name: "edit", text: { edit: "", cancel: "", update: "" }},
{ name: "destroy", text:""}
],
title: "Actions"
}
],
dataSource: dataSource,
sortable: {
mode: "single",
allowUnsort: false
},
dataBound: function(e) {
setToolTip();
},
edit: function(e) {
$('.k-grid-update').kendoTooltip({content: "Update"});
$('.k-grid-cancel').kendoTooltip({content: "Cancel"});
},
cancel: function(e) {
setToolTip();
},
editable: {
mode: "inline",
confirmation: "Are you sure that you want to delete this record?"
}
});
Drop down function is defined as:
function calculationTypeDropDownEditor(container, options) {
$('<input required data-text-field="name" data-value-field="id" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
autoBind: false,
dataSource: {
transport: {
read: {
dataType: "jsonp",
url: baseURL + "rips/services/calculationType/lookupList"
}
}
}
});
}
After doing some search on Google and browsing through different examples on Kendo site, I finally was able to resolve this issue. Following is my understanding of the problem and solution:
When we are using drop down box or combo box as a custom editor, generally we have a different datasource that contains a list options with an id and a value to show. I defined the template as "#=field.property#" of the field that I was looking up. In my case it was calculation type. Following is my model:
model: {
id: "serviceId",
fields: {
serviceName: { field:"serviceName", type: "string", validation: { required: { message: "Service Name is required"}} },
billCalculationType: { field: "billCalculationType", validation: { required: true}},
payCalculationType: { field: "payCalculationType", validation: { required: true} }
}
In above, billCalculationType and payCalculationType are supposed to be drop down list values displaying the calculation type name but storing the id of the corresponding calculation type. So, in my grid definition, I added following:
{ field: "billCalculationType",
editor: calculationTypeDropDownEditor,
template:"#=billCalculationType.name#",
title: "Bill Calculation Type" },
Where calculation dropdown editor is a function that builds a drop down from external data source. So, it works fine. However, for the template definition to work in (field.property) format, the server must return the value as a class for this field and not a simple text. So, in my server service, I returned in following format:
{"billCalculationType":{"id":"4028828542b66b3a0142b66b3b780001","name":"Hourly","requiredDetails":false},"payCalculationType":{"id":"4028828542b66b3a0142b66b3b960002","name":"Kilometers","requiredDetails":false},"serviceId":"4028828542b66b3a0142b66b3c16000a","serviceName":"XYZ"}
Notice that the billCalculationType and payCalculationType are returned as objects with name and id as properties. This allows the template to work properly.
Hope this helps.
One of ASP.NET's security features is proving to be a mountain to scale here - the "d" property addition when returning a JSON response appears to be confusing ExtJS when I attempt to reconfigure a gridpanel dynamically, causing it to fail when attempting to generate new column structure.
I followed this solution by nicholasnet:
http://www.sencha.com/forum/showthread.php?179861-Dynamic-grid-columns-store-fields
and it works beautifully, until the JSON payload is wrapped around the "d" property, e.g.
{"d":{
"metaData": {
"root": "data",
"fields": [{
"type": "int",
"name": "id",
"hidden": true,
"header": "id",
"groupable": false,
"dataIndex": "id"
}, ...omitted for brevity...]
},
"success": true,
"data": [{
"id": "1",
"controller": "Permissions",
"description": "Allow to see permission by roles",
"administrator": true,
"marketing": false
}]
}
}
I can't work out how to tell ExtJS to skirt around this problem. I've tried setting the "root" property of the AJAX reader to "d.data" but that results in the grid showing the correct number of rows but no data at all.
I've all the property descriptors required for column metadata ("name", "header", "dataIndex") in the JSON so I don't believe the JSON structure to be the cause. My main lead at the moment is that on the event handler:
store.on
({
'load' :
{
fn: function(store, records, success, operation, eOpts)
{
grid.reconfigure(store,store.proxy.reader.fields);
},
scope: this
}
}, this);
The fields in historyStore.proxy.reader.fields part is undefined when I pass the "d"-wrapped JSON. Anyone have any ideas on why this is or how to solve this issue?
edit: my Store/proxy
Ext.define('pr.store.Store-History', {
extend: 'Ext.data.Store',
model: 'pr.model.Model-History',
proxy: {
type: 'ajax',
url: '/data/history.json',
reader: {
type: 'json',
root: 'd'
}
}
});
Ext.define('pr.store.Store-History', {
extend: 'Ext.data.Store',
model: 'pr.model.Model-History',
proxy: {
type: 'ajax',
url: '/data/history.json',
reader: {
type: 'json',
root: 'data',
readRecords: function(data) {
//this has to be before the call to super because we use the meta data in the superclass readRecords
var rootNode = this.getRoot(data);
if (rootNode.metaData) {
this.onMetaChange(rootNode.metaData); // data used to update fields
}
/**
* #deprecated will be removed in Ext JS 5.0. This is just a copy of this.rawData - use that instead
* #property {Object} jsonData
*/
this.jsonData = rootNode;
return this.callParent([rootNode]); // data used to get root element and then get data from it
},
}
}
});
Update:
you are not getting fields in reader because the default code for getting fields from data doesn't handle your wrapped data, so you need to change 'readRecords' function to handle your custom data
I am missing something very basic, my comboxbox never appears, can somebody please look at the following code and tell me what I am missing, I have tried both .Select and ComboBox as type and I ma using dojo-1.5
var layout4 =
[
{ field: "abbr", name: "Abbreviation", width: 10 },
{ field: "name", name: "Name", width: 10 },
{ field: "capital", name: "Capital", width: '10'},
{ field: "combo", name: "combo", width: 10,
type: dojox.grid.cells.Select,
options: [ "new", "read", "replied" ],
editable:true
}
];
var store4 = { identifier: 'abbr',
label: 'name',
items: [
{ abbr:'ec', name:'Ecuador', capital:'Quito', combo:'' },
{ abbr:'eg', name:'Egypt', capital:'Cairo', combo:''},
{ abbr:'sv', name:'El Salvador', capital:'San Salvador', combo:''},
{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo', combo:''},
{ abbr:'er', name:'Eritrea', capital:'Asmara', combo:'' },
{ abbr:'ee', name:'Estonia', capital:'Tallinn', combo:''},
{ abbr:'et', name:'Ethiopia', capital:'Addis Ababa', combo:'' }
]};
storeData = new dojo.data.ItemFileReadStore(
{ data:store4}
);
// create a new grid:
var grid4 = new dojox.grid.DataGrid({
query: { abbr: '*' },
store: storeData,
clientSort: true,
rowSelector: '20px',
structure: layout4
}, document.createElement('div'));
// append the new grid to the div "gridContainer4":
dojo.byId("gridContainer4").appendChild(grid4.domNode);
// Call startup, in order to render the grid:
grid4.startup();
Try replacing the long line that you have using appendChild() with this one:
grid4.placeAt("gridContainer4");
Your code is rather scrambled and without seeing the whole thing it's a little hard to debug. Do you get any errors on the console? Can you post a complete example on JSFiddle?
The reason was that I was using ItemFileReadStore, and it was not allowed to edit an item in store and so combobox was not appearing. Using WriteStore solves this problem here. Ofcourse it was dumb to use readsotre.
Now I have a different problem where I want combobox to appear in grid where canEdit is implemented, but that is a different question.