Hi I am trying to build a question and answer based on conditional flows.
Let's take my question in UI is below JSON:
{
"text": "What is the best cookie?",
"type": "mc",
"answers": [
"Chocolate Chip",
"Sugar",
"Beer"
],
"answer": "Sugar"
}
Let's take if the user selects Sugar and Beer as an option, I have put up a question from below JSON which maps to the selected answer if he chooses Beer then a different question from the JSON object.
If the user answers A and B for the first question, then the next question should be 3rd object in JSON, if C then 2nd Object from JSON, if C and A then the first Object from JSON.
Below is entire mock JSON I have
{
"title": "Quiz about Foo",
"questions": [
{
"text": "Is true true?",
"type": "tf",
"answer": "t"
},
{
"text": "Is false true?",
"type": "tf",
"answer": "f"
},
{
"text": "What is the best beer?",
"type": "mc",
"answers": [
"Coors",
"Miller",
"Bud",
"Anchor Steam"
],
"answer": "Anchor Steam"
},
{
"text": "What is the best cookie?",
"type": "mc",
"answers": [
"Chocolate Chip",
"Sugar",
"Beer"
],
"answer": "Sugar"
}
]
}
I'm not sure I fully understand your question. If you want each answer to point to the next question in your JSON, you have to add some kind of a question ID. You also need to convert your answers from strings to objects, so you can add the ID of the next question to them.
Something like:
{
"questions": [
{
"id": 1,
"text": "What is the best cookie?",
"type": "mc",
"answers": [
{ "text": "Chocolate Chip", "nextQuestionId": 2 },
{ "text": "Sugar", "nextQuestionId": 2 },
{ "text": "Beer", "nextQuestionId": 3 }
],
"answer": "Sugar"
},
{
"id": 2,
"text": "Second question?",
...
},
{
"id": 3,
"text": "Third question?",
...
}
]
}
This way you can write a simple generic logic that just follows the flow defined by the JSON.
Related
This is my sessionState object
{
"sessionAttributes": {},
"dialogAction": {
"type": "ElicitSlot",
"slotToElicit": "flowName"
},
"intent": {
"name": "WelcomeIntent",
"confirmationState": "None",
"slots": {
"flowName": null
},
"state": "Fulfilled"
}
this is messages array
[
{
"contentType": "ImageResponseCard",
"content": "Some content",
"imageResponseCard": {
"title": "Choose option",
"subtitle": "options are",
"buttons": [
{
"text": "option1",
"value": "option1"
},
{
"text": "option2",
"value": "option2"
},
{
"text": "option3",
"value": "option3"
},
{
"text": "option4",
"value": "option4"
},
{
"text": "option5",
"value": "option5"
},
{
"text": "option6",
"value": "option6"
},
{
"text": "option7",
"value": "option7"
}
]
}
}
]
iam sending 7 buttons from lamda function, but lex is not accepting more than 5 buttons. It is giving error saying buttons should be between 0,5 index. Is there way to display more than 5 buttons in lex response.
As per the developer guide, ImageResponseCard supports a maximum of 5 button objects.
Array Members: Minimum number of 0 items. Maximum number of 5 items.
ImageResponseCard - AWS Lex V2 Developer Guide
I took the approach of conditionally eliciting different cards after a previous slot. In my case, choose a risk level (High, Medium, Low) and depending on which value, elicit either a High, Med, or low slot card prompt. Just a workaround.
I have this JSON which I'm parsing using NodeJS and it needs to be restructured into the second JSON which I've added below.
In the first JSON, the rows object has two pages objects (any number of pages objects can be present) which contains all the same keys and values with the exception of values and display keys.
{
"pages": [
{
"label": "SomeLabel",
"name": "Some",
"sections": [
{
"type": "Repeat",
"label": "Label 1",
"name": "Name 1",
"rows": [
{
"pages": [
{
"label": "Label 1",
"name": "Name 1",
"sections": [
{
"type": "Flow",
"label": "Label 2",
"name": "Name 2",
"answers": [
{
"label": "Question Label",
"question": "Question",
"values": [
"Value A"
],
"valuesMetadata": [
{
"display": "Display A",
"row": {
"columns": []
}
}
]
}
]
}
]
}
]
},
{
"pages": [
{
"label": "Label 1",
"name": "Name 1",
"sections": [
{
"type": "Flow",
"label": "Label 2",
"name": "Name 2",
"answers": [
{
"label": "Question Label",
"question": "Question",
"values": [
"Value B"
],
"valuesMetadata": [
{
"display": "Display B",
"row": {
"columns": []
}
}
]
}
]
}
]
}
]
}
],
"footer": null
}
]
}
]
}
In the second JSON the rows object has a single pages object, inside of which the values and display keys have multiple values (the non-common values).
{
"pages": [
{
"label": "SomeLabel",
"name": "Some",
"sections": [
{
"type": "Repeat",
"label": "Label 1",
"name": "Name 1",
"rows": [
{
"pages": [
{
"label": "Label 1",
"name": "Name 1",
"sections": [
{
"type": "Flow",
"label": "Label 2",
"name": "Name 2",
"answers": [
{
"label": "Question Label",
"question": "Question",
"values": [
"Value A",
"Value B"
],
"valuesMetadata": [
{
"display": [
"Display A",
"Display B"
],
"row": {
"columns": []
}
}
]
}
]
}
]
}
]
}
],
"footer": null
}
]
}
]
}
So, I want to know the fast and easy steps to do this. Please let me know the process and methods to solve this.
Thanks
If I understand you correctly, you want to combine all pages in a single page that holds all information.
This can be achieved using the Array.reduce function. reduce takes an array and combines all elements to a single value using a function (provided by you) to combine the first two elements until only one is left (i.e. 1 * 2 => new1; new1 * 3 => new2 where * represents your function).
Your problem would look something like this:
rows[0].pages = rows[0].pages.reduce((currentElement, currentState) => {
if (!currentState) { // first iteration return first element but make sure display is an array
currentElement.sections[0].answers[0].valuesMetadata[0].display =
[currentElement.sections[0].answers[0].valuesMetadata[0].display];
return currentElement;
}
// add values of current element to arrays in current state
currentState.sections[0].answers[0].values
.concat(currentElement.sections[0].answers[0].values);
currentState.sections[0].answers[0].valuesMetadata[0].display
.concat(currentElement.sections[0].answers[0].valuesMetadata[0].display);
return currentState;
});
currentElement is the object of the array that is currently reduced, currentState is the intermediate result of the reduction.
PS:
The object looks like you are way too many arrays where you would not need them. The given code snippet works only for the first element in each array (hence the [0]s. If you really do have multiple values in each array you would have to iterate over all of those accordingly.
I am trying to merge json format (prefably using underscore) but not sure how it could be done. The first json has no indicator of _id to be mapped.
JSON 1:
{
"0001": {
"answer": "sad"
},
"0002": {
"answer": "sad1"
}
}
JSON 2:
[
{
"_id": "0001",
"question": "who am I"
},
{
"_id": "0002",
"question": "How old are you?"
}
]
Final Result after merging:
[
{
"_id": "0001",
"question": "who am I",
"answer": "sad"
},
{
"_id": "0002",
"question": "How old are you?",
"answer": "sad1"
}
]
For the approach, i am trying to transform JSON 1 to following format first but unable to achieve.
[
{
"_id": "0001",
"answer": "sad"
},
{
"_id": "0002",
"answer": "sad1"
}
]
Ok, so you can do a foreach to add the new answer element:
var json1 = {
"0001": {
"answer": "sad"
},
"0002": {
"answer": "sad1"
}
};
var json2 = [
{
"_id": "0001",
"question": "who am I"
},
{
"_id": "0002",
"question": "How old are you?"
}
];
json2.forEach(function(o) {
o.answer = json1[o._id].answer;
});
console.log(json2);
I hope that helps :D
Having a thorny problem and only see similar but also simpler solutions on SO.
Is is possible to generate a dynamic key AND dynamic values using JS/JSON?
For instance, let's say I have JSON like this:
{
"email": "user#someco.com",
"firstname": "Bob",
"lastname": "Smith",
"company": "ACME",
"custom": {
"services": [
{
"name": "svc1",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc2",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc3",
"desc": "abcdefg",
"selected": "false",
"status": "None"
},
{
"name": "svc4",
"desc": "abcdefg",
"selected": "false",
"status": "None"
}
],
"fields": [
{
"name": "Products",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Product1",
"desc": "abcdef"
},
{
"name": "Product2",
"desc": "abcdef"
}
],
"services": [
"svc1",
"svc2",
"svc3"
]
},
{
"name": "Wines",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Wine 1",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
},
{
"name": "Fruits",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Fruit 1",
"desc": "abcdef"
},
{
"name": "Fruit 2",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
}
]
}
};
I need to go into the fields and for each field (products, wines, fruits) see if a given service is contained within so that I can go back and generate a product or wine or fruit for each service that requires it. But I don't want to repeat the services names more than once. The resulting JSON should look something like this:
{"svc1":["Products"], "svc2":["Products"], "svc3":["Products"], "svc4":["Fruits", "Wines"]}
The hope would be that to generate a dynamic list in Angular I can just turn and loop back through this JSON, pulling out the values for each product, fruit, wine, whatever.
I've been trying a lot of nested for loops and the like but whenever I get more than one layer down the dynamism seems to stop. I'm guessing that for this to work I need to move between JS Objects and JSON?
Right now I'm trying something like this, which isn't quite working, stringify or no. And maybe I'm flip-flopping too much between JSON and JS Objects:
var outObj = [];
var fieldItems;
$.each(jsonObj.custom.fields, function(key, item) {
fieldItems = item;
fieldItems.name = item.name;
$.each(fieldItems.services, function(key, item) {
var serviceName = item;
//check to see if the serviceName already exists
if (outObj.indexOf(serviceName) > -1) {
outObj.serviceName.push(fieldItems.name);
} else {
outObj.push(serviceName);
}
});
});
JSON.stringify(outObj);
console.log("outObj " + outObj);
I get "can't read property 'push' of undefined" errors and the like. Seems this should be possible from a single nested loop, but maybe I need to just do two passes? Any other suggestions?
To me it sounds like overcomplicated solution. You can use basic array methods of javascript to filter out required structure. I am not sure what profiling_value in the presented snippet, so I started from the object structure in OP
var desiredResult = jsonObj.custom.services.reduce(function(result, service){
result[service.name] = jsonObj.custom.fields.filter(function(field){
return field.services.indexOf(service.name) >= 0;
}).map(function(field){ return field.name; });
return result;
}, {});
This gives the expected result for mentioned object.
reduce is required to iterate over all services and accumulate result in one object. Then for each service fields are iterated to filter out only those that contain link to this service. And finally list of filtered fields is transformed (map) into list of strings - their names - and inserted into accumulator
I would like to create a view in CouchDb which contains some fields from multiple linked documents.
My documents are something like this:
/*Products:*/
{
"_id": "Products:ABC",
"doctype": "Products",
"productCode": "ABC",
"description": "The best product you ever seen",
"category_id": "Categories:1",
"brand_id": "Brands:52"
},
{
"_id": "Products:DEF",
"doctype": "Products",
"productCode": "DEF",
"description": "DEFinitely a good product",
"category_id": "Categories:2",
"brand_id": "Brands:53"
},
/*Categories*/
{
"_id": "Categories:1",
"categoryID": "1",
"description": "Awesome products"
},
{
"_id": "Categories:2",
"categoryID": "2",
"description": "Wonderful supplies"
},
/*Brands*/
{
"_id": "Brands:52",
"brandID": "52",
"description": "Best Items"
},
{
"_id": "Brands:53",
"brandID": "53",
"description": "Great Gadgets"
},
I would like to have a result like this:
/*View results: */
{
"id": "Products:ABC",
"key": "Products:ABC",
"value": {
"productCode": "ABC",
"description": "The best product you ever seen",
"category": {
"categoryID": "1",
"description": "Awesome products"
},
"brand": {
"brandID": "52",
"description": "Best Items"
}
}
},
{
"id": "Products:DEF",
"key": "Products:DEF",
"value": {
"productCode": "DEF",
"description": "DEFinitely a good product",
"category": {
"categoryID": "2",
"description": "Wonderful supplies"
},
"brand": {
"brandID": "53",
"description": "Great Gadgets"
}
}
},
The goal is to have a result that is a join between the three documents. Is it possibile?
As you can imagine I come from the SQL world, so maybe I am designing the database terribly wrong, so any advice on how to change the documents structure is welcome!
Thanks in advance!
Francesco
There are two ways to do this:
Use the query() API and linked documents (search the page for "linked documents")
Use the relational-pouch plugin
The advantage of the relational-pouch plugin is that, under the hood, it is faster than linked documents because it doesn't rely on building up a map/reduce index. The advantage of linked documents is that it is the more traditional way of solving this problem in CouchDB, and it doesn't rely on an extra plugin. Choose whichever one you like. :)
Edit: re-reading your question, I see you want to join 3 different document types together. Currently that is not possible with linked documents (you can only "join" two types), whereas it is possible with relational-pouch. So I guess that makes the decision easy. :)