Related
I am querying a DynamoDB. It has an attribute called 'Multiple Units' with the following structure: List [ Map { Map { S }, S }, ... ]
I test a lambda locally:
module.exports.getByAddress = async (event) => {
const params = {
TableName: process.env.tableName,
Key: {
Address: event.pathParameters.address
}
};
var docClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
docClient.get(params).promise().then(
returnResult => console.log(returnResult)
)
}
This is the output:
Item: {
...
license: '',
Coordinates: { lng: '-71.075985', lat: '42.346096' },
'Multiple Units': [ [Object], [Object], [Object], [Object], [Object], [Object] ],
...
}
When I attempt to console.log Multiple Units list specifically, I get undefined.
In reading about DynamoDB get/getItem, I am guessing it has to do with async but I cannot configure a change that will result in correct output.
Based on your comment, you mention that you're getting undefined when you execute console.log(returnResult['Multiple Units']).
Take a closer look at what console.log(returnResult) is printing:
Item: {
...
license: '',
Coordinates: { lng: '-71.075985', lat: '42.346096' },
'Multiple Units': [ [Object], [Object], [Object], [Object], [Object], [Object] ],
...
}
Notice that it's printing a map with the key of Item. Therefore, to get at your data, try to console.log(returnResult.Item['Multiple Units'])
You can check out the DynamoDB SDK API for more info regarding the result of a get call.
This question already has answers here:
Can we add text field dynamically
(2 answers)
Closed 2 years ago.
I'm having a problem retrieving the activityID of a Choice prompt once the selection has been made within a waterfall dialog. Im currently making use of a Teams channel.
An example my code can be found below. In the step after the selection, if I have a look at the stepContext object(found further below), there is reference of an Activity.id, but this id is infact the Activity id for the current step. I'm sure I'm missing something simple, but cant figure it out.
async step1(step) {
const choice1 = await step.prompt(CHOICE_PROMPT, {
prompt: 'Please select one of the following:',
choices: ChoiceFactory.toChoices(['Option1', 'Option2', 'Option3'])
});
return choice1
}
async step2(step) {
console.log(step)
console.log("...........................................................................")
return await step.prompt(NAME_PROMPT, 'Please insert your name')
}
WaterfallStepContext {
dialogs:
DialogSet {
dialogs:
{ NAME_PROMPT: [Object],
CHOICE_PROMPT: [Object],
CONFIRM_PROMPT: [Object],
ATTACHMENT_PROMPT: [Object],
WATERFALL_DIALOG: [Object] },
dialogState: undefined },
context:
TurnContext {
_respondedRef: { responded: false },
_turnState:
Map {
Symbol(BotIdentity) => [Object],
Symbol(ConnectorClient) => [Object],
Symbol(OAuthScope) => 'https://api.botframework.com',
'botCallbackHandler' => [AsyncFunction],
Symbol(state) => [Object],
Symbol(ActivityReceivedEmitted) => true },
_onSendActivities: [],
_onUpdateActivity: [],
_onDeleteActivity: [],
bufferedReplyActivities: [],
_adapter:
BotFrameworkAdapter {
middleware: [Object],
BotIdentityKey: Symbol(BotIdentity),
OAuthScopeKey: Symbol(OAuthScope),
ConnectorClientKey: Symbol(ConnectorClient),
TokenApiClientCredentialsKey: Symbol(TokenApiClientCredentials),
settings: [Object],
credentials: [Object],
credentialsProvider: [Object],
isEmulatingOAuthCards: false,
authConfiguration: [Object],
turnError: [AsyncFunction] },
_activity:
{ text: 'Option1',
textFormat: 'plain',
type: 'message',
timestamp: 2020-05-05T13:32:42.187Z,
localTimestamp: 2020-05-05T13:32:42.187Z,
id: '1588685562137',
channelId: 'msteams',
serviceUrl: 'https://smba.trafficmanager.net/za/',
from: [Object],
conversation: [Object],
recipient: [Object],
entities: [Array],
channelData: [Object],
locale: 'en-US' } },
stack: [ { id: 'WATERFALL_DIALOG', state: [Object] } ],
state: DialogStateManager { dialogContext: [Circular] },
_info:
{ index: 1,
options: {},
reason: 'endCalled',
result: { value: 'Option1', index: 0, score: 1, synonym: 'Option1' },
values: { instanceId: 'b5bef7ce-1c43-e1db-abc0-651ed2b5bb8f' },
onNext: [Function: onNext] },
parent:
DialogContext {
dialogs: DialogSet { dialogs: [Object], dialogState: [Object] },
context:
TurnContext {
_respondedRef: [Object],
_turnState: [Object],
_onSendActivities: [],
_onUpdateActivity: [],
_onDeleteActivity: [],
bufferedReplyActivities: [],
_adapter: [Object],
_activity: [Object] },
stack: [ [Object] ],
You're not missing anything simple. This is actually sort of difficult to do because Microsoft Teams does not include any information about the button that sent an action to your bot.
In order to get the activity ID that an action came from, you have to save the ID in bot state on the turn that you send the activity. The ID can be found in the resource response returned by whichever method you use to send the activity. Unfortunately, this means you can't let the prompt send the card for you because then you wouldn't be able to access the resource response.
If you want to save more than one activity ID at a time, you'll need a way of knowing which one is associated with each incoming action. This means you'll have to include metadata in the actions you put in your cards and save that metadata along with the activity ID in your bot state.
If you'd like an easier or even an automatic way of doing all this, please voice your support for the cards library that I'm currently working on: https://github.com/BotBuilderCommunity/botbuilder-community-dotnet/issues/137
I need help figuring out how to save the output from my array. I have tried appending the output to a csv, but this gives me an empty csv or a csv appended with the words [object] for each item in the array.
Here is a sample of the output in my array:
{
date: '2014-01-25',
firstBoxerRating: [Array],
firstBoxerWeight: 235.5,
judges: [Array],
links: [Object],
location: 'Golden Nugget Casino, Atlantic City',
metadata: 'Joseph Pasquale 75-77 | Tony Perez 78-74 | Barbara Perez 78-74\n' +
'<br>',
numberOfRounds: [Array],
outcome: 'win',
rating: 20,
referee: [Object],
result: [Array],
secondBoxer: [Object],
secondBoxerLast6: [Array],
secondBoxerRating: [Array],
secondBoxerRecord: [Object],
secondBoxerWeight: 236.5,
titles: []
},
{
date: '2014-05-16',
firstBoxerRating: [Array],
firstBoxerWeight: 240.75,
judges: [Array],
links: [Object],
location: '2300 Arena, Philadelphia',
metadata: 'Pierre Benoist 79-73 | Lynne Carter 78-74 | Eric Dali 79-73\n' +
'<br>',
numberOfRounds: [Array],
outcome: 'win',
rating: 20,
referee: [Object],
result: [Array],
secondBoxer: [Object],
secondBoxerLast6: [Array],
secondBoxerRating: [Array],
secondBoxerRecord: [Object],
secondBoxerWeight: 238,
titles: []
},
{
date: '2014-08-02',
firstBoxerRating: [Array],
firstBoxerWeight: 236.5,
judges: [Array],
links: [Object],
location: 'Revel Resort, Atlantic City',
metadata: ' time: 1:48\n' +
' | Lindsey Page\n' +
'<br>Williams down three times\n' +
'<br>',
numberOfRounds: [Array],
outcome: 'win',
rating: 20,
referee: [Object],
result: [Array],
secondBoxer: [Object],
secondBoxerLast6: [Array],
secondBoxerRating: [Array],
secondBoxerRecord: [Object],
secondBoxerWeight: 233,
titles: []
},
{
date: '2014-09-19',
firstBoxerRating: [Array],
firstBoxerWeight: 237,
judges: [Array],
links: [Object],
location: "Harrah's Philadelphia, Chester",
metadata: ' time: 1:34\n' +
' | <span>referee:</span> Benjy Esteves Jr<span> | </span>Bernard Bruni | Larry Hazzard Jr | Alan Rubenstein\n' +
'<br>',
numberOfRounds: [Array],
outcome: 'win',
rating: 20,
referee: [Object],
result: [Array],
secondBoxer: [Object],
secondBoxerLast6: [Array],
secondBoxerRating: [Array],
secondBoxerRecord: [Object],
secondBoxerWeight: 288,
titles: []
},
{
date: '2014-11-14',
firstBoxerRating: [Array],
firstBoxerWeight: 244,
judges: [Array],
links: [Object],
location: "Harrah's Philadelphia, Chester",
metadata: ' time: 2:28\n' +
' | <span>referee:</span> Benjy Esteves Jr<span> | </span>Eric Dali | Larry Hazzard Jr | Mike Somma\n' +
'<br>',
numberOfRounds: [Array],
outcome: 'win',
rating: 40,
referee: [Object],
result: [Array],
secondBoxer: [Object],
secondBoxerLast6: [Array],
secondBoxerRating: [Array],
secondBoxerRecord: [Object],
secondBoxerWeight: 209,
titles: []
},
I am assuming that this output is a JSON object.
This is the code I used to produce this output:
async function writeData() {
const csv = require('csv-parser')
const results = [];
fs.createReadStream('C:\\Users\\User\\Documents\\testingclean.csv')
.pipe(csv())
.on('data',(data)=> results.push(data))
.on('end', async () => {
const cookieJar = await getCookieJar();
const promises = [];
results.forEach((data) => {
promises.push(boxrec.getPersonById(cookieJar,data.id));
})
const fighters = await Promise.all(promises); // Fighters is an array
fighters.forEach((fighter) => {
console.log(fighter.output);
})
});
};
try {
writeData();
} catch (error) {
console.log("Error in writeData: " + error);
}
Something like this should work.
fighters.forEach((fighter) => {
let data = '';
for (const key in fighter.output) {
if (Array.isArray(fighter.output[key])) {
data += JSON.stringify(fighter.output[key]) + ',';
} else if (typeof fighter.output[key] === 'object') {
data += JSON.stringify(fighter.output[key]) + ',';
} else {
data += fighter.output[key] + ',';
}
}
data = data.replace(/(^,)|(,$)/g, ""); // Remove trailing comma
data += '\n'; // Add new line
fs.appendFile('data.csv', data, (err) => {
if (err) throw err;
});
});
Didn't test the code. Also, the data.csv file might take some time to create depending on data size. The forEach look will finish even before nodejs is done with writing file. So, the program might exit but in the background writing might go on until its done. You have to maintain the async execution part. How to handle it is not in scope of this question.
I have integrated Neo4j in my NodeJS (backend) and Angular6 (front-end) application. My query runs and i get the data of nodes and connected node network in my Neo4j Browser. However, i want that entire data of nodes being displayed through a particular query on my console (i.e. in NodeJS -> back-end and angular ->front-end). This is not happening . I get only the first node data. Please help me retrieve the entire displayed nodal data in NodeJS .
NodeJS code
neo4j-controller.js
// Require Neo4j
var neo4j = require('neo4j-driver').v1;
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');
var express = require('express');
var router = express.Router();
var app = express();
const driver = new neo4j.driver("bolt://localhost:11001", neo4j.auth.basic("neo4j", "ib1"));
const cypher = 'MATCH (n) RETURN count(n) as count';
app.set('views', path.join(__dirname, 'views'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
var session = driver.session();
var request = require('request');
router.post('/', seekParameter);
module.exports = router;
//working code below
// ------------------------------- Original Code ----------------------------------------
function seekParameter(req, res) {
console.log("INSIDE NODE JS CONTROLLER OF seekParameter");
console.log("BODY IS ", req.body);
session
.run(`MATCH p=()-[r:Parameter]->() RETURN p`)
.then(function (result){
result.records.forEach(function(record){
console.log("record = ", record);
console.log("result = ", result)
console.log("1] record._fields[0].properties=",record._fields[0].properties);
res.send(record);
});
})
.catch(function(err){
console.log("inside catch = " + err);
})
session.close();
}
output
INSIDE NODE JS CONTROLLER OF seekParameter
BODY IS undefined
record = Record {
keys: [ 'p' ],
length: 1,
_fields:
[ Path { start: [Object], end: [Object], segments: [Array], length: 1 } ],
_fieldLookup: { p: 0 } }
result = { records:
[ Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] } ],
summary:
ResultSummary {
statement:
{ text: ' MATCH p=()-[r:Parameter]->() RETURN p ;',
parameters: {} },
statementType: 'r',
counters: StatementStatistics { _stats: [Object] },
updateStatistics: StatementStatistics { _stats: [Object] },
plan: false,
profile: false,
notifications: [],
server: ServerInfo { address: 'localhost:11001', version: 'Neo4j/3.4.7' },
resultConsumedAfter: Integer { low: 9, high: 0 },
resultAvailableAfter: Integer { low: 1, high: 0 } } }
1] record._fields[0].properties= { name: 'accidentTime' }
2]record._fields[1] = [ Path {
start: Node { identity: [Object], labels: [Array], properties: [Object] },
end: Node { identity: [Object], labels: [Array], properties: [Object] },
segments: [ [Object] ],
length: 1 } ]
record = Record {
keys: [ 'p' ],
length: 1,
_fields:
[ Path { start: [Object], end: [Object], segments: [Array], length: 1 } ],
_fieldLookup: { p: 0 } }
result = { records:
[ Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] },
Record {
keys: [Array],
length: 1,
_fields: [Array],
_fieldLookup: [Object] } ],
summary:
ResultSummary {
statement:
{ text: ' MATCH p=()-[r:Parameter]->() RETURN p ;',
parameters: {} },
statementType: 'r',
counters: StatementStatistics { _stats: [Object] },
updateStatistics: StatementStatistics { _stats: [Object] },
plan: false,
profile: false,
notifications: [],
server: ServerInfo { address: 'localhost:11001', version: 'Neo4j/3.4.7' },
resultConsumedAfter: Integer { low: 9, high: 0 },
resultAvailableAfter: Integer { low: 1, high: 0 } } }
1] record._fields[0].properties= { name: 'productType' }
2]record._fields[1] = [ Path {
start: Node { identity: [Object], labels: [Array], properties: [Object] },
end: Node { identity: [Object], labels: [Array], properties: [Object] },
segments: [ [Object] ],
length: 1 } ]
inside catch = Error: Can't set headers after they are sent.
Thanks. I resolved the issue.
The place and parameter i was passing in response was incorrect.
Correct code -
session
.run(` MATCH p=()-[r:Parameter]->() RETURN p ;`)
.then(function (result){
result.records.forEach(function(record){
console.log("record = ", record);
console.log("result = ", result)
console.log("1] record._fields[0].properties = ",record._fields[0].end.properties);
// res.send(record);
});
res.send(result);
})
.catch(function(err){
console.log("inside catch = " + err);
})
session.close();
}
I'm trying to produce a lean record for a REST API that include virtual fields.
The official documentation for how to implement virtual fields for Mongoose:
http://mongoosejs.com/docs/guide.html
My model:
var keystone = require('keystone')
, Types = keystone.Field.Types
, list = new keystone.List('Vendors');
list.add({
name : {
first: {type : Types.Text}
, last: {type : Types.Text}
}
});
list.schema.virtual('name.full').get(function() {
return this.name.first + ' ' + this.name.last;
});
list.register();
Now, let's query the model:
var keystone = require('keystone'),
vendors = keystone.list('Vendors');
vendors.model.find()
.exec(function(err, doc){
console.log(doc)
});
Virtual field name.full is not here:
[ { _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White' } }]
But if we do this:
vendors.model.find()
.exec(function(err, doc){
console.log(doc.name.full); // "Walter White"
});
Then the virtual shows.
I guess the reason is that when I do a console.log(doc) the Mongoose document.toString() method is invoked which does not include virtuals by default. Fair enough. That's understandable.
To include the virtuals in any of the conversion methods you have to go:
doc.toString({virtuals: true})
doc.toObject({virtuals: true})
doc.toJSON({virtuals: true})
However, this includes keys I don't want for my REST API to pump out to my users:
{ _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White', full: 'Walter White' },
_: { name: { last: [Object], first: [Object] } },
list:
List {
options:
{ schema: [Object],
noedit: false,
nocreate: false,
nodelete: false,
autocreate: false,
sortable: false,
hidden: false,
track: false,
inherits: false,
searchFields: '__name__',
defaultSort: '__default__',
defaultColumns: '__name__',
label: 'Vendors' },
key: 'Vendors',
path: 'vendors',
schema:
Schema {
paths: [Object],
subpaths: {},
virtuals: [Object],
nested: [Object],
inherits: {},
callQueue: [],
_indexes: [],
methods: [Object],
statics: {},
tree: [Object],
_requiredpaths: [],
discriminatorMapping: undefined,
_indexedpaths: undefined,
options: [Object] },
schemaFields: [ [Object] ],
uiElements: [ [Object], [Object] ],
underscoreMethods: { name: [Object] },
fields: { 'name.first': [Object], 'name.last': [Object] },
fieldTypes: { text: true },
relationships: {},
mappings:
{ name: null,
createdBy: null,
createdOn: null,
modifiedBy: null,
modifiedOn: null },
model:
{ [Function: model]
base: [Object],
modelName: 'Vendors',
model: [Function: model],
db: [Object],
discriminators: undefined,
schema: [Object],
options: undefined,
collection: [Object] } },
id: '563acf280f2b2dfd4f59bcf3' }
I can always of course just delete the unwanted keys, but this doesn't seem quite right:
vendors.model.findOne()
.exec(function(err, doc){
var c = doc.toObject({virtuals: true});
delete c.list;
delete c._;
console.log(c)
});
This produces what I need:
{ _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White', full: 'Walter White' },
id: '563acf280f2b2dfd4f59bcf3' }
Is there not a better way of getting a lean record?
I think you want the select method.. something like this:
vendors.model.findOne()
.select('_id __v name').
.exec(function(err, doc){
console.log(c)
});
Also personally I prefer setting virtuals: true on the schema rather than the document, but depends on use case I guess.
One solution would be to use a module like Lodash (or Underscore) which allows you pick a whitelist of property names:
vendors.model.findOne()
.exec(function(err, doc){
var c = _.pick(doc, ['id', 'name.first', 'name.last', 'name.full']);
console.log(c)
});
Given your use-case of serving this data via REST API, I think explicitly defining a whitelist of property names is safer. You could even define a virtual property on your schema which returns the predefined whitelist:
list.schema.virtual('whitelist').get(function() {
return ['id', 'name.first', 'name.last', 'name.full'];
});
and use it in multiple places, or have different versions of your whitelist, all managed at the model layer.