async await inside function not working properly? - javascript

I have this function, that i need to define an async function inside it:
_refetchConnection = (page) => { // query for cursor page
const refetchVariables = async (fragmentVariables) => {
let pageCursor;
if(page !== 1) {
const getAfterCursorQueryText = `
query($count: Int!, $cursor:String) {# filename+Query
viewer {
publicTodos (first: $count, after: $cursor) {
edges {
cursor
node {
id
}
}
pageInfo { # for pagination
hasPreviousPage
startCursor
hasNextPage
endCursor
}
}
}
}`;
let cursor = fragmentVariables.cursor;
let count = 5;
const getAfterCursorQuery = { text: getAfterCursorQueryText };
const result = await this.props.relay.environment._network.fetch(getAfterCursorQuery, {cursor, count});
pageCursor = result.data.viewer.publicTodos.pageInfo.endCursor;
} else if (page === 1) {
pageCursor = null;
}
return {
cursor: pageCursor,
count:5
}
}
this.props.relay.refetch(refetchVariables, null);
};
but there's no returned value on refetchVariables, it only had when I do not use async but i need to perform await for this code, and I need access on fragmentVariables:
const result = await this.props.relay.environment._network.fetch(getAfterCursorQuery, {cursor, count});
maybe making refetchVariables not an async works? but I have no idea how to code it. help? btw this is the value returned on async refetchVariables:
ƒ refetchVariables(_x2) {
return _ref3.apply(this, arguments);
}

Related

How to read a lot of documents (1M+) from a collection in Cloud Firestore?

The code below fails with error 9 FAILED_PRECONDITION: The requested snapshot version is too old.
const ref = db.collection('Collection');
const snapshot = await ref.get();
snapshot.forEach((doc,index) => {
...use data
})
Getting all documents from one collection in Firestore
EDIT:
getData();
async function getData(doc) {
let snapshot = await global.db.collection('Collection').orderBy().startAfter(doc).limit(5000).get();
const last = snapshot.docs[snapshot.docs.length - 1];
snapshot.forEach((doc,index) => {
//...use data
})
if (snapshot.docs.length < 5000) {
return;
}
else {
getData(last)
}
}
EDIT 2 (works, a bit slow, reads sequentially, 5000 docs at a time):
let snapshot = null;
let totalIndex = 0;
await getData();
async function getData(doc) {
if (!doc) {
const first = await global.db.collection("collection").doc("docID");
snapshot = await global.db.collection('collection').orderBy(admin.firestore.FieldPath.documentId()).startAt(first).limit(5000).get();
}
else {
snapshot = await global.db.collection('Prompts').orderBy(admin.firestore.FieldPath.documentId()).startAfter(doc).limit(5000).get();
}
const last = snapshot.docs[snapshot.docs.length - 1];
snapshot.forEach((doc,index) => {
console.log(totalIndex++);
//...use data
})
if (snapshot.docs.length < 5000) {
return;
}
else {
getData(last)
}
}
Since you're initially calling getData() without any arguments, that leads to doc being undefined in that function body. And calling startAfter(undefined) is not valid.
What you'll want to do is optionally adding that startAfter with something like:
async function getData(doc) {
let query = global.db.collection('Collection').orderBy();
if (doc) {
query = query.startAfter(doc);
}
let snapshot = await query.limit(5000).get();
...

How to reduce repeated strapi api calls

I have the following code
const getData = async (): Promise<void> => {
const { page, pageSize } = pageOption
try {
setShowContentLoader(true)
const { data: isActiveData } = await axiosStrapi.get('/changelog-sellers?isActive=true&_sort=id:DESC')
const { data: pageOptionRows } = await axiosStrapi.get(`/changelog-sellers?_start=${(page - 1) * pageSize}&_limit=${pageSize}&_sort=id:DESC`)
const { data: rows } = await axiosStrapi.get(`/changelog-sellers?type=${type}&_start=${(page - 1) * pageSize}&_limit=${pageSize}&_sort=id:DESC`)
const { data: oldRows } = await axiosStrapi.get('/changelog-sellers?_start=0&_limit=10&_sort=id:DESC')
setFeaturedPosts(isActiveData.slice(0, 3))
setOldChangelogSellers(oldRows)
if (type === 'all') {
const { data: count } = await axiosStrapi.get('/changelog-sellers/count')
setTotal(count)
setChangelogSellers(pageOptionRows)
} else {
const { data: tabTitleCount } = await axiosStrapi.get(`/changelog-sellers/count?type=${type}`)
setTotal(tabTitleCount)
setChangelogSellers(rows)
}
} catch (error) {
console.log('error', error)
} finally {
setShowContentLoader(false)
}
}
I am repeatedly calling /changelog-sellers to get different kinds of data. Is there a way to simplify my code so that I only call /changelog-sellers once? Or is it impossible because I need to pass different parameters to each of the different api call even though they are all sourced from /changelog-sellers?

How to make recursive promise calls?

I am working with an API that gives me data with a limit per request (here 25). Therefore, I have to recursively make promises with fetch. However, while most of my logic works, when I try to return from the function it will return an empty array. The image below will make it more clear.
const url = (conf_name) => {
return (
"https://api.elsevier.com/content/search/scopus?view=COMPLETE&cursor=*&query=CONFNAME(" +
conf_name +
")%20AND%20DOCTYPE(cp)%20AND%20SRCTYPE(p)&field=dc:creator,dc:title,dc:description,affilname,affiliation-city,affiliation-country,authkeywords,prism:doi,prism:doi,prism:coverDate"
);
};
const savePapers = (json, conf_name) => {
let temp = new Array();
for (let i = 0; i < json["search-results"]["entry"].length; i++) {
temp[i] = {
title: json["search-results"]["entry"][i]["dc:title"],
author: json["search-results"]["entry"][i]["dc:creator"],
publication_date: json["search-results"]["entry"][i]["prism:coverDate"],
doi: json["search-results"]["entry"][i]["prism:doi"],
abstract: json["search-results"]["entry"][i]["dc:description"],
author_keywords: json["search-results"]["entry"][i]["authkeywords"],
proceeding: conf_name,
};
}
return temp;
};
async function getPapers(final, url, conf_name) {
let total_amount_of_papers;
let next;
let position = 2;
try {
let response = await fetch(url, options);
let json = await response.json();
total_amount_of_papers = json["search-results"]["opensearch:totalResults"];
if (json["search-results"]["link"][position]["#ref"] == "prev")
next = json["search-results"]["link"][position + 1]["#href"];
next = json["search-results"]["link"][position]["#href"];
final = final.concat(savePapers(json, conf_name));
if (final.length === 50) {
console.log("hey",final.length);
return final;
}
await getPapers(final, next, conf_name);
} catch (error) {
console.log(error);
}
}
const createNewConf = async (conferences) => {
let final = new Array();
try {
var temp = new Conference({
acronym: conferences.acronym,
name: conferences.fullname,
area: conferences.area,
subarea: conferences.subarea,
location: conferences.location,
url: conferences.url,
description: conferences.description,
papers: await getPapers(final, url(conferences.acronym),conferences.acronym),
});
console.log(temp.papers.length);
} catch (error) {
console.log(error);
}
return temp;
};
describe("Saving records", function () {
it("Saved records to the database", async function (done) {
var conferences = [];
try {
for (var i = 0; i <= 1; i++) {
conferences[i] = await createNewConf(json_conferences[i]);
conferences[i].save().then(function () {
assert(conferences[i].isNew === True);
done();
});
}
mongoose.connection.close();
} catch (error) {
console.log(error);
}
});
});
Below you can see the length of my final array after passing the if to stop fetching more. and the second number is what I receive in the initial call
Console
Maybe anyone has an idea of the undefined behavior that occurs during return.
Your help is much appreciated.

How to measure the time of several calls of async function

I have a problem with understanding how do async functions in js work. So I need to call async function for 5 times and measure the duration of every execution. In the end I should have an array with 5 time values.
I have smth like this
for (let i = 0; i < 5; i++) {
const run = async () => {
await test(thisTest, filename, unitTestDict);
};
measure(run).then(report => {
// inspect
const {tSyncOnly, tSyncAsync} = report;
// array.push(tSyncAsync)
console.log(`∑ = ${tSyncAsync}ms \t`);
}).catch(e => {
console.error(e)
});
}
Here I found the realization of time measure function:
class Stack {
constructor() {
this._array = []
}
push(x) {
return this._array.push(x)
}
peek() {
return this._array[this._array.length - 1]
}
pop() {
return this._array.pop()
}
get is_not_empty() {
return this._array.length > 0
}
}
class Timer {
constructor() {
this._records = new Map
/* of {start:number, end:number} */
}
starts(scope) {
const detail =
this._records.set(scope, {
start: this.timestamp(),
end: -1,
})
}
ends(scope) {
this._records.get(scope).end = this.timestamp()
}
timestamp() {
return performance.now()
}
timediff(t0, t1) {
return Math.abs(t0 - t1)
}
report(scopes, detail) {
let tSyncOnly = 0;
let tSyncAsync = 0;
for (const [scope, {start, end}] of this._records)
if (scopes.has(scope))
if (~end) {
tSyncOnly += end - start;
tSyncAsync += end - start;
const {type, offset} = detail.get(scope);
if (type === "Timeout")
tSyncAsync += offset;
}
return {tSyncOnly, tSyncAsync}
}
}
async function measure(asyncFn) {
const stack = new Stack;
const scopes = new Set;
const timer = new Timer;
const detail = new Map;
const hook = createHook({
init(scope, type, parent, resource) {
if (type === 'TIMERWRAP') return;
scopes.add(scope);
detail.set(scope, {
type: type,
offset: type === 'Timeout' ? resource._idleTimeout : 0
})
},
before(scope) {
if (stack.is_not_empty) timer.ends(stack.peek());
stack.push(scope);
timer.starts(scope)
},
after() {
timer.ends(stack.pop())
}
});
return await new Promise(r => {
hook.enable();
setTimeout(() => {
asyncFn()
.then(() => hook.disable())
.then(() => r(timer.report(scopes, detail)))
.catch(console.error)
}, 1)
})
}
I can call it inside the loop and get console.log with time for every iteration:
measure(run).then(report => {
// inspect
const {tSyncOnly, tSyncAsync} = report;
// array.push(tSyncAsync)
console.log(`∑ = ${tSyncAsync}ms \t`);
}).catch(e => {
console.error(e)
});
But when I try to push this console values to array, nothing comes out, the array remains empty. Is there a way to fill it in?

How to use dialogs with dispatch service?

I cannot use beginDialog with the LUIS dispatch. I want to use processHomeAutomation function to begin a new dialog but it gives me an error.
[onTurnError]: Error: DialogContext.beginDialog(): A dialog with an id
of 'TOP_LEVEL_DIALOG' wasn't found.
I imported TOP_LEVEL_DIALOG but still does not work. It only works with MainDialog which is the name of the current class.
const { ConfirmPrompt, DialogSet, DialogTurnStatus, OAuthPrompt, WaterfallDialog } = require('botbuilder-dialogs');
const { LogoutDialog } = require('./logoutDialog');
const { TopLevelDialog, TOP_LEVEL_DIALOG } = require('./topLevelDialog');
const { LuisRecognizer, QnAMaker } = require('botbuilder-ai');
const CONFIRM_PROMPT = 'ConfirmPrompt';
const MAIN_DIALOG = 'MainDialog';
const MAIN_WATERFALL_DIALOG = 'MainWaterfallDialog';
const OAUTH_PROMPT = 'OAuthPrompt';
let loggedIn = true;
class MainDialog extends LogoutDialog {
constructor() {
super(MAIN_DIALOG, process.env.connectionName);
this.addDialog(new TopLevelDialog());
this.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.connectionName,
text: 'Please Sign In',
title: 'Sign In',
timeout: 300000
}));
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.loginStep.bind(this),
this.displayTokenPhase1.bind(this),
this.displayTokenPhase2.bind(this)
]));
}
/**
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} dialogContext
*/
async run(context, accessor) {
console.log(this.id)
if (loggedIn) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(context);
const results = await dialogContext.continueDialog();
const dispatchRecognizer = new LuisRecognizer({
applicationId: process.env.LuisAppId,
endpointKey: process.env.LuisAPIKey,
endpoint: `https://${process.env.LuisAPIHostName}.api.cognitive.microsoft.com`
}, {
includeAllIntents: true,
includeInstanceData: true
}, true);
const qnaMaker = new QnAMaker({
knowledgeBaseId: process.env.QnAKnowledgebaseId,
endpointKey: process.env.QnAAuthKey,
host: process.env.QnAEndpointHostName
});
this.dispatchRecognizer = dispatchRecognizer;
this.qnaMaker = qnaMaker;
const recognizerResult = await dispatchRecognizer.recognize(context);
// Top intent tell us which cognitive service to use.
const intent = LuisRecognizer.topIntent(recognizerResult);
// Next, we call the dispatcher with the top intent.
await this.dispatchToTopIntentAsync(context, intent, recognizerResult, dialogContext, results, dialogSet);
} else {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(context);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
console.log(this.id)
await dialogContext.beginDialog(this.id);
}
}
}
async promptStep(stepContext) {
return await stepContext.beginDialog(OAUTH_PROMPT);
}
async loginStep(stepContext) {
// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
const tokenResponse = stepContext.result;
if (tokenResponse) {
loggedIn = true;
await stepContext.context.sendActivity('You are now logged in.');
return await stepContext.prompt(CONFIRM_PROMPT, 'Would you like to view your token?');
}
await stepContext.context.sendActivity('Login was not successful please try again.');
return await stepContext.endDialog();
}
async displayTokenPhase1(stepContext) {
await stepContext.context.sendActivity('Thank you.');
const result = stepContext.result;
if (result) {
return await stepContext.beginDialog(OAUTH_PROMPT);
}
return await stepContext.endDialog();
}
async displayTokenPhase2(stepContext) {
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity(`Here is your token ${tokenResponse.token}`);
}
return await stepContext.endDialog();
}
/// QNA STUFF STATS HERE
async dispatchToTopIntentAsync(context, intent, recognizerResult, dialogContext, results) {
switch (intent) {
case 'automation':
await this.processHomeAutomation(context, recognizerResult.luisResult, dialogContext, results);
break;
case 'qna':
await this.processSampleQnA(context);
break;
default:
this.logger.log(`Dispatch unrecognized intent: ${intent}.`);
await context.sendActivity(`Dispatch unrecognized intent: ${intent}.`);
break;
}
}
async processHomeAutomation(context, luisResult, dialogContext, results, dialogSet) {
return await dialogContext.beginDialog(TOP_LEVEL_DIALOG);
}
async processSampleQnA(context) {
this.logger.log('processSampleQnA');
const results = await this.qnaMaker.getAnswers(context);
if (results.length > 0) {
await context.sendActivity(`${results[0].answer}`);
} else {
await context.sendActivity('Sorry, could not find an answer in the Q and A system.');
}
}
}
module.exports.MainDialog = MainDialog;

Categories

Resources