Collection id: By index or by value? - collections

Maybe I don't know what to search for this, but I tried "[json] id as index or value".
I am curious what others' experience teaches regarding this. I have a number of rest calls that return JSON data from a database. Among the values, are unique identifiers. My question is,
Is it better to provide the IDs as fields on the items, or as an index on items. For example:
{
dataByValue: [
{ id: 1, data: "What's up?", otherData: "hi" },
{ id: 2, data: 123, otherData: "hi" }
],
dataByIndex: {
1: { data: "What's up?", otherData: "hi" },
2: { data: 123, otherData: "hi" }
},
orMaybeBoth: {
1: { id: 1, data: "What's up?", otherData: "hi" },
2: { id: 2, data: 123, otherData: "hi" }
}
}
I realize this is not valid JSON, but you get the picture.
I have some thoughts on why each may be beneficial:
By value may be easier to loop through, especially on platforms that don't have an easy way to handle variable keys on objects.
By index allows you to quickly access the data if you do have the ID.

Related

Normalized ngrx entities id reference

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)

Pacts: Matching rule for non-empty map (or a field which is not null) needed

I need help with writing my consumer Pacts using pact-jvm (https://github.com/DiUS/pact-jvm).
My problem is I have a field which is a list (an array) of maps. Each map can have elements of different types (strings or sub-maps), eg.
"validatedAnswers": [
{
"type": "typeA",
"answers": {
"favourite_colour": "Blue",
"correspondence_address": {
"line_1": "Main St",
"postcode": "1A 2BC",
"town": "London"
}
}
},
{
"type": "typeB",
"answers": {
"first_name": "Firstname",
"last_name": "Lastname",
}
}
]
but we're only interested in some of those answers.
NOTE: The above is only an example showing the structure of validatedAnswers. Each answers map has dozens of elements.
What we really need is this: https://github.com/pact-foundation/pact-specification/issues/38, but it's planned for v.4. In the meantime we're trying a different approach. What I'm attempting to do now is to specify that each element of the list is a non-empty map. Another approach is to specify that each element of the list is not null. Can any of this be done using Groovy DSL?
This:
new PactBuilder().serviceConsumer('A').hasPactWith('B')
.port(findAvailablePort()).uponReceiving(...)
.willRespondWith(status: 200, headers: ['Content-Type': 'application/json'])
.withBody {
validatedAnswers minLike(1) {
type string()
answers {
}
}
}
doesn't work because it mean answers is expected to be empty ("Expected an empty Map but received Map( [...] )", see also https://github.com/DiUS/pact-jvm/issues/298).
So what I would like to do is something like this:
.withBody {
validatedAnswers minLike(1) {
type string()
answers Matchers.map()
}
}
or:
validatedAnswers minLike(1) {
type string()
answers {
keyLike 'title', notNull()
}
}
or:
validatedAnswers minLike(1) {
type string()
answers notNull()
}
Can it be done?
I would create two separate tests for this, one test for each of the different response shapes and have a provider state for each e.g. given there are type b answers.
This way when you verify on provider side, it will only send those two field types.
The union of the two examples gives a contract that allows both.
You can do it without DSL, sample Groovy script:
class ValidateAnswers {
static main(args) {
/* Array with some samples */
List<Map> answersList = [
[
type: 'typeA',
answers: [
favourite_colour: 'Blue',
correspondence_address: [
line_1: 'Main St',
postcode: '1A 2BC',
town: 'London'
]
]
],
[
type: 'typeB',
answers: [
first_name: 'Firstname',
last_name: "Lastname"
]
],
[
type: 'typeC',
answers: null
],
[
type: 'typeD'
],
[
type: 'typeE',
answers: [:]
]
]
/* Iterating through all elements in list above */
for (answer in answersList) {
/* Print result of checking */
println "$answer.type is ${validAnswer(answer) ? 'valid' : 'not valid'}"
}
}
/**
* Method to recursive iterate through Map's.
* return true only if value is not an empty Map and it key is 'answer'.
*/
static Boolean validAnswer(Map map, Boolean result = false) {
map.each { key, value ->
if (key == 'answers') {
result = value instanceof Map && value.size() > 0
} else if (value instanceof Map) {
validAnswer(value as Map, false)
}
}
return result
}
}
Output is:
typeA is valid
typeB is valid
typeC is not valid
typeD is not valid
typeE is not valid

How to search array of objects by id when that id is within another array (JsonPath)?

I'm trying to use JsonPath to filter an array of objects by id. For each item in the array I want to filter it if its id is in a second array.
So for example I have the source array:
[
{
id: 1,
name: "House"
},
{
id: 2,
name: "Hamer"
},
{
id: 13,
name: "Book"
},
{
id: 45,
name: "Truck"
},
]
And I want to filter this array by id, if that id is in another array, for example:
[ 2, 13]
This should result in a filtered array of:
[
{
id: 2,
name: "Hamer"
},
{
id: 13,
name: "Book"
}
]
I can figure out how to do this with a lengthy or statement with each item in the second array, but that seems like a pretty painful and silly way to filter one array by another.
How can I perform the above operation using JsonPath, but without an or for each array item in the second array?
getItemsById = (arr, arr2) => {
result = arr.filter(f => arr2.includes(f.id));
console.log(result);
}

How to Remove from List Of Maps in DynamoDB (Must be Atomic)

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.

Can you use combineReducers to compose deep state reducers?

Redux docs suggest using normalizr to design the shape of the state like this:
{
entities: {
cards: {
42: {
id: 42,
text: 'Hello',
category: 2
},
43: {
id: 53,
text: 'There?',
category: 1
},
}
categories: {
1: {
id: 1,
name: 'Questions'
}
2: {
id: 2,
name: 'Greetings'
},
}
},
filter: 'SHOW_ALL',
allCardsList: {
isFetching: false,
items: [ 42, 43 ]
},
}
Naturally, this would split into three composable reducers (filter, allThingsList and entities), but it seems to me that I'd want to write separate reducers for entities.cards and entities.categories.
Is there a way to split management of entities into subreducers that would allow composition like this:
let rootReducer = combineReducers({
entities: {
things,
categories
},
filter,
allCardsList
});
Are there any advantages to keeping the cards and categories in entities, instead of keeping on the root level (which will allow composition using combineReducers)?
{
cards: { ... },
categories: { ... },
filter: 'SHOW_ALL',
allCardsList: { ... }
}
Is there a way to split management of entities into subreducers that would allow composition like this?
Sure! combineReducers() just gives you a reducer so you can use it several times:
let rootReducer = combineReducers({
entities: combineReducers({
things,
categories
}),
filter,
allCardsList
});
The shopping-cart example in Redux repo demonstrates this approach.
Are there any advantages to keeping the cards and categories in entities, instead of keeping on the root level?
It’s up to you but I find the structure you suggest easier to work with. It’s indeed easier for understanding to group all entities under a single key, and it is possible with combineReducers() as I show above.

Resources