Any smart JSON/JS Object counting packages? - json

I don't mean to be duplicating any questions, since I have read so many great answers here on StackOverflow.
Given the below JSON data:
[
{
“department”: “vice”,
“team”: [
{
"selected": "Yes"
},
{
“selected": “No”
}
],
“fund”: [
“team_a”
“team_c”
]
}
]
I want to return a count of selected, so from the above 'yes'=1 and 'no'=1.
I understand I can do it through for loop, using a simple countYes++ to return the answer, however I have 2 questions as below:
Is there any other way (i.e. using some npm package).
In my example the options are simple Yes and No, if I have a bigger list of things to count, how to count all unique ones > 0?
Thanks.

I tried to write using vanilla JS you can look for library like underscore, lodash for more options.
var data = [
{
"department": "vice",
"team": [
{
"selected": "Yes"
},
{
"selected": "No"
}
],
"fund": [
"team_a",
"team_c"
]
},
{
"department": "vice",
"team": [
{
"selected": "Yes"
},
{
"selected": "Yes"
}
],
"fund": [
"team_a",
"team_c"
]
},
{
"department": "vice",
"team": [
{
"selected": "Yes"
},
{
"selected": "No"
}
],
"fund": [
"team_a",
"team_c"
]
}
];
function decisionReducer(prev, next) {
var team = next.team;
if (team && Array.isArray(team)) {
team.forEach(function (row) {
if (row.selected === 'Yes') {
prev.yes += 1;
}
if (row.selected === 'No') {
prev.no += 1;
}
})
}
return prev;
};
var counter = data.reduce(decisionReducer, {yes: 0, no: 0})
console.log(counter);

Related

ES6 filter an array of objects retrieving a field that is an empty array or does not contain certain value

I am trying to filter the following array
const matches = [
{
"match": "1",
"teams": [
[
{ "name": "david"},
{ "name": "tom"}
],
[
{ "name": "liam"},
{ "name": "noah"}
]
]
},
{
"match": "2",
"teams": [
[
{ "name": "david"},
{ "name": "tom"}
],
[
{ "name": "oliver"},
{ "name": "elijah"}
]
]
},
{
"match": "3",
"teams": []
}
]
I want to retrieve the objects where the teams array is empty, or "oliver" does not belong to the teams. It should retrieve match "1" and "3"
I tried the following
matches.filter(match => match.teams.length === 0 || !match.teams.includes({ name: "oliver" })
matches.filter(match => match.teams.length === 0 || !match.teams.some(team => team.name === "oliver" })
but I am getting the 3 objects
match.teams is an array of arrays of players
try this
matches.filter(match =>
match.teams.length === 0 ||
match.teams.every(team =>
team.every(player => player.name !== "oliver" )
)
)
// use array.flat method. teams is arrays of arrays
const result=matches.filter(match=>{
if(!match.teams.length){
return true;
}
const teamArray=match.teams.flat(1);
console.log(teamArray);
const search=teamArray.find(player=>player.name!=="oliver");
if(search){
return true;
}
return false;
});

Postman test - How can I search the entire response for a specific value?

Sorry for the noob question.
Using Postman, how can I search the entire response for a specific value? In this case the value I am using as my assertion would be let’s say “222222”, this has been set as an environment variable (“provId”) in another request and I need to be able to assert that it appears in this second request.
Below is a small snippet of the response I’m working with, the acual response would be much larger and the value “222222” could appear anywhere within.
[
{
“eventId”: “123456”,
“mappings”: [{
“provider”: “ABC”,
“providerId”: “111111”,
“confidence”: 1.0
}
]
},
{
“eventId”: “246810”,
“mappings”: [{
“provider”: “ABC”,
“providerId”: “222222”,
“confidence”: 1.0
}
]
},
{
“eventId”: “135791”,
“mappings”: [{
“provider”: “ABC”,
“providerId”: “333333”,
“confidence”: 1.0
}
]
}
]
I have managed to write a bit of code to check the correct value from the 1st object (below) but I need it to search the whole response.
const body = pm.response.json();
pm.test(“placeholder” + pm.variables.get(“provId”), function() {
pm.response.to.have.jsonBody("[0][mappings].[0][providerId]",
pm.variables.get(“provId”) );
});
let a =
[
{
"eventId": "123456",
"mappings": [{
"provider": "ABC",
"providerId": "111111",
"confidence": 1.0
}
]
},
{
"eventId": "246810",
"mappings": [{
"provider": "ABC",
"providerId": "222222",
"confidence": 1.0
}
]
},
{
"eventId": "135791",
"mappings": [{
"provider": "ABC",
"providerId": "333333",
"confidence": 1.0
}
]
}
]
console.log(a.find(elem => elem.mappings[0].providerId === "333333"))
use array.find
Update as per comment , if you dont know the mapping index then:
console.log(a.find(elem => {
return elem.mappings.find(items=>items.providerId==="333333")
}
))
Solution;
var resp = pm.response.json();
console.log(resp);
for (var i = 0;i<resp.length;i++)
{
if (resp[i].mappings[0].providerId == pm.variables.get(“provId”))
{
console.log("PASSED TEST : " +resp[i].eventId);
}
else
{
console.log("FAILED TEST : " +resp[i].eventId);
}
}

Return selected JSON object from mongo find method

Here is the sample JSON
Sample JSON:
[
{
"_id": "123456789",
"YEAR": "2019",
"VERSION": "2019.Version",
"QUESTION_GROUPS": [
{
"QUESTIONS": [
{
"QUESTION_NAME": "STATE_CODE",
"QUESTION_VALUE": "MH"
},
{
"QUESTION_NAME": "COUNTY_NAME",
"QUESTION_VALUE": "IN"
}
]
},
{
"QUESTIONS": [
{
"QUESTION_NAME": "STATE_CODE",
"QUESTION_VALUE": "UP"
},
{
"QUESTION_NAME": "COUNTY_NAME",
"QUESTION_VALUE": "IN"
}
]
}
]
}
]
Query that am using :
db.collection.find({},
{
"QUESTION_GROUPS.QUESTIONS.QUESTION_NAME": "STATE_CODE"
})
My requirement is retrive all QUESTION_VALUE whose QUESTION_NAME is equals to STATE_CODE.
Thanks in Advance.
If I get you well, What you are trying to do is something like:
db.collection.find(
{
"QUESTION_GROUPS.QUESTIONS.QUESTION_NAME": "STATE_CODE"
},
{
"QUESTION_GROUPS.QUESTIONS.QUESTION_VALUE": 1
})
Attention: you will get ALL the "QUESTION_VALUE" for ANY document which has a QUESTION_GROUPS.QUESTIONS.QUESTION_NAME with that value.
Attention 2: You will get also the _Id. It is by default.
In case you would like to skip those issues, you may need to use Aggregations, and unwind the "QUESTION_GROUPS"-> "QUESTIONS". This way you can skip both the irrelevant results, and the _id field.
It sounds like you want to unwind the arrays and grab only the question values back
Try this
db.collection.aggregate([
{
$unwind: "$QUESTION_GROUPS"
},
{
$unwind: "$QUESTION_GROUPS.QUESTIONS"
},
{
$match: {
"QUESTION_GROUPS.QUESTIONS.QUESTION_NAME": "STATE_CODE"
}
},
{
$project: {
"QUESTION_GROUPS.QUESTIONS.QUESTION_VALUE": 1
}
}
])

Set next step for the waterfall dialogue in Microsoft BotBuilder NodeJS SDK

I am using Microsoft Bot Framework for my facebook messenger bot. I want to load the dialog data from json files instead of hard coding in the js file. I would like to configure the next step in the dialog, based on result from the "current" step, which is part of the json file configuration, something like this.
{
"name": "welcome",
"type": "waterfall",
"steps": [
{
"id": 0,
"data": [
{
"type": "text",
"value": "Hey, It's nice to meet you."
},
{
"type": "quickReplies",
"value": "What do you want to do next?",
"options": [
{
"text": "some option 1",
"value": "option1"
},
{
"text": "some option 2",
"value": "option2"
}
]
}
],
"next": [
{
"result": "option1",
"action": "goto step 2"
},
{
"result": "option2",
"action": "goto step 5"
}
]
}
]
}
I would like to process all the incoming messages and respond with correct dialog or correct step in the dialog for the user.
I am trying something like this;
handleMessage = function (session) {
var step = session.dialogData["BotBuilder.Data.WaterfallStep"] || 0;
// check response data from previou step and identify the next step.
// set the waterfall step id
session.dialogData["BotBuilder.Data.WaterfallStep"] = 2;
session.send("Hello");
}
var bot = new builder.UniversalBot(connector, function (session) {
handleMessage(session);
})
.set('storage',tableStorage);
With this code, I am always getting step as zero for session.dialogData["BotBuilder.Data.WaterfallStep"] even after setting this to a different number.
Also, as soon as I set the waterfall step number, all other state data that is stored in my table storage for this conversation is gone.
Storage data before setting waterfall step:
{
"BotBuilder.Data.SessionState": {
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 0
}
},
{
"id": "*:welcome",
"state": {
"BotBuilder.Data.WaterfallStep": 1
}
},
{
"id": "BotBuilder:prompt-text",
"state": {
"options": {
"prompt": {
"type": "message",
"agent": "botbuilder",
"source": "facebook",
"address": {
"id": "mid.$cAAAlr-0LRH9niO21L1hV6hs83GuJ",
"channelId": "facebook",
"user": {
"id": "XXXX",
"name": "XXXX"
},
"conversation": {
"isGroup": false,
"id": "XX"
},
"bot": {
"id": "XXX",
"name": "XXX"
},
"serviceUrl": "https://facebook.botframework.com"
},
"text": "what do you want to next"
//ignored for simplicity
},
"promptAfterAction": true,
"libraryNamespace": "*"
},
"turns": 0,
"lastTurn": 1517594116372,
"isReprompt": false
}
}
],
"lastAccess": 1517594112740,
"version": 0
}
}
After I set the waterfall step:
{
"BotBuilder.Data.SessionState": {
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 2
}
}
],
"lastAccess": 1517602122416,
"version": 0
}
}
Interestingly the step number is saved to the database (but in session state) but my "session" variable do not have this value anywhere. Also, even after configuring custom state service, the serviceUrl is still https://facebook.botframework.com which I thought is the default state service used if there is no state service set for the bot.
Per your code, as your bot actually contains only one waterfall step: handleMessage(session);, which raised your issue. You can consider to create multiple dialogs from json configration instead of complex waterfall steps.
Here is my quick test, for your information:
const json = `
[{
"name": "welcome",
"type": "waterfall",
"steps": [
{
"id": 0,
"data": [
{
"type": "text",
"value": "Hey, It's nice to meet you."
},
{
"type": "quickReplies",
"value": "What do you want to do next?",
"options": [
{
"text": "some option 1",
"value": "option1"
},
{
"text": "some option 2",
"value": "option2"
}
]
}
],
"next": [
{
"result": "option1",
"action": "dialog2"
},
{
"result": "option2",
"action": "dialog3"
}
]
}
]
},{
"name":"dialog2",
"type": "waterfall",
"steps": [
{
"data": [
{
"type": "text",
"value": "Hey, this is dialig2."
}]
}
]
},{
"name":"dialog3",
"type": "waterfall",
"steps": [
{
"data": [
{
"type": "text",
"value": "Hey, this is dialig3."
}]
}
]
}]
`;
const generateSignleStep = (step) => {
return (session, args, next) => {
step.forEach(sentence => {
switch (sentence.type) {
case 'quickReplies':
let choices = sentence.options.map(item => {
return item.value
});
let card = new builder.ThumbnailCard(session)
.text(sentence.value)
.buttons(sentence.options.map(choice => new builder.CardAction.imBack(session, choice.value, choice.text)))
let message = new builder.Message(session).addAttachment(card);
builder.Prompts.choice(session, message, choices);
break;
case 'text':
default:
session.send(sentence.value)
break;
}
})
}
}
const generatenextAction = (actions) => {
return (session, args, next) => {
const response = args.response;
actions.map(action => {
if (action.result == response.entity) {
session.beginDialog(action.action);
}
})
}
}
const generateWaterfallSteps = (steps) => {
let waterfall = [];
steps.forEach(step => {
waterfall.push(generateSignleStep(step.data));
if (step.next) {
waterfall.push(generatenextAction(step.next));
}
});
return waterfall;
}
var bot = new builder.UniversalBot(connector);
const jsonobj = JSON.parse(json);
jsonobj.forEach(dialog => {
bot.dialog(dialog.name, generateWaterfallSteps(dialog.steps))
.triggerAction({
matches: new RegExp(dialog.name, "g")
})
});
The result is:

Mongodb insert with multiple conditions

I'm having multiple documents in a collection, each document has this data structure :
{
_id: "some object id",
data1: [
{
data2_id : 13233,
data2: [
{
sub_data1: "text1",
sub_data2: "text2",
sub_data3: "text3",
},
{
sub_data1: "text4",
sub_data2: "text5",
sub_data3: "text6",
}
]
},
{
data2_id : 53233,
data2: [
{
sub_data1: "text4",
sub_data2: "text5",
sub_data3: "text6",
}
...
]
},
{
data2_id : 56233,
data2: [
{
sub_data1: "text7",
sub_data2: "text8",
sub_data3: "text9",
}
...
]
},
{
data2_id : 53236,
data2: [
{
sub_data1: "text10",
sub_data2: "text22",
sub_data3: "text33",
}
...
]
}
]
}
I'd like to update to a set of ids that maches some condition, update only the sub object within the document.
I've tries this:
db.collection.update({
"$and": [
{
"_id": {
"$in": [
{
"$id": "54369aca9bc25af3ca8b4568"
},
{
"$id": "54369aca9bc25af3ca8b4562"
}
]
}
},
{
"data1.data2": {
"$elemMatch": {
"sub_data1": "text4",
"sub_data2": "text5"
}
}
}
]
},
{
"data1.data2.$.sub_data3" : "text updated"
}
)
But I get the following error:
Update of data into MongoDB failed: dev.**.com:27017: cannot use the part (data2 of data1.data2.0.sub_data3) to traverse the element...
Any Ideas?
There is an open issue here that imposes a limitation when trying to update elements of an array nested within another array.
Besides, there are some improvements you can do here:
For your query you don't need the $and
db.collection.update(
{
"_id": {
"$in": [
{"$id": "54369aca9bc25af3ca8b4568"},
{"$id": "54369aca9bc25af3ca8b4562"}
]},
"data1.data2": {
"$elemMatch": {
"sub_data1": "text4",
"sub_data2": "text5"
}
},{..update...})
You might want to use $set:
db.collection.update(query,{ $set:{"name": "Mike"} })
Otherwise, you might lose the rest of the data within your document.