I'm using the libraby request for my ajax call, this library give me a response and after I'm using JSON.
I've got a constant id inside and where I'm block is to use this constant outside the request()
I know that I need a promises but I don't understand how to use it ...
const options = {
***
},
};
request(options, function(error, response, issue) {
const json = JSON.parse(issue);
for (let i = 0; i < json.versions.length; i++) {
const test = json.versions[i].name;
if (test === version) {
const id = json.versions[i].id; //here id
}
}
});
console.log(id); // I need to retrieve the const id here but id it's undefined, so how can I specified id
Try using:
const options = {
***
},
};
let id;
function getMyBody(options, callback) {
request(options, function(error, response, issue) {
const json = JSON.parse(issue);
for (let i = 0; i < json.versions.length; i++) {
const test = json.versions[i].name;
if (test === version) {
const id = json.versions[i].id; //here id
callback(id);
}
}
});
});
}
getMyBody(options,(id)=>{this.id = id; console.log(id);})
Use callback function
let id = 0;
fetchData = () => {
console.log(`id before ${id}`)
fetch('api', { method: 'GET',
headers: { 'Authorization': ** } })
.then((res) {
onCompleted(res)
}):;
}
onCompleted = (data) => {
id = data;
console.log(`id after ${id}`)
}
fetchData();
Simply create a variable outside the callback and assign it inside the callback result
var id
const options = {
***
},
};
request(options, function(error, response, issue) {
const json = JSON.parse(issue);
for (let i = 0; i < json.versions.length; i++) {
const test = json.versions[i].name;
if (test === version) {
id = json.versions[i].id; // here id is the id we declared in line 1.
}
}
});
console.log(id);
The value of id is going to be undefined at console.log(id); because the http request has not yet executed completely. You can either use callbacks, or a promise or a setInterval for id to be defined.
Using setInterval
var id
const options = {
***
},
};
request(options, function(error, response, issue) {
const json = JSON.parse(issue);
for (let i = 0; i < json.versions.length; i++) {
const test = json.versions[i].name;
if (test === version) {
id = json.versions[i].id; // here id is the id we declared in line 1.
}
}
});
var _interval = setInterval(() => {
if(id !== undefined) {
console.log(id);
// clearing interval
clearInterval(_interval)
}
}, 1000)
Using promise
below is an example of how to convert your request into a promise and then use the id
const options = {};
const promised_request = () => new Promise((resolve, reject) => {
request(options, function (error, response, issue) {
if (error) {
return reject(error);
}
const json = JSON.parse(issue);
for (let i = 0; i < json.versions.length; i++) {
const test = json.versions[i].name;
if (test === version) {
const id = json.versions[i].id;
return resolve(id);
}
}
});
});
promised_request().then((id) => {
// use your id here
console.log(id);
});
Related
Hello so a little bit of background.
I created a function in JS that fetches some data(multiple objects that can change in number every time I fetch the data ad example : fetch1: I get 3 obj | fetch2: I get 1 obj, I CAN NOT GET 0 obj ) from a website every minute, processes that data, and then sends it to the cloud firestore. The problem is that after the upload of the data, the doc and the collection get deleted without any reason at all and I don't understand what is happening.
I tried to search online but I could not find a fix.
Can anyone give me a hint of what is happening ?
This is the function in JS
import functions = require("firebase-functions");
import admin = require("firebase-admin");
admin.initializeApp();
const database = admin.firestore();
import https = require("https");
let finalData: { [x: string]: any; }[] = [];
const page = 1;
const fiat = "";
const tradeType = "";
const asset = "";
const payTypes = [""];
const baseObj = {
page,
rows: ,
publisherType: ,
asset,
tradeType,
fiat,
payTypes,
};
const stringData = JSON.stringify(baseObj);
const options = {
hostname: "",
port: ,
path: "",
method: "",
headers: {
"Content-Type": "application/json",
"Content-Length": stringData.length,
},
};
const req = https.request(options, (res: any) => {
finalData = [];
let output = "";
res.on("data", (d: string) => {
output += d;
});
res.on("end", () => {
try {
const jsonOuput = JSON.parse(output);
const allData = jsonOuput["data"];
for (let i = 0; i < allData.length; i++) {
let payTypesz = "";
for (let y = 0; y < allData[i]["adv"]["tradeMethods"].length; y++) {
payTypesz += allData[i]["adv"]["tradeMethods"][y]["payType"];
if (y < allData[i]["adv"]["tradeMethods"].length - 1) {
payTypesz += ", ";
}
}
const obj = {
tradeType: allData[i]["adv"]["tradeType"],
asset: allData[i]["adv"]["asset"],
fiatUnit: allData[i]["adv"]["fiatUnit"],
price: allData[i]["adv"]["price"],
surplusAmount: allData[i]["adv"]["surplusAmount"],
maxSingleTransAmount: allData[i]["adv"]["maxSingleTransAmount"],
minSingleTransAmount: allData[i]["adv"]["minSingleTransAmount"],
nickName: allData[i]["advertiser"]["nickName"],
monthOrderCount: allData[i]["advertiser"]["monthOrderCount"],
monthFinishRate: allData[i]["advertiser"]["monthFinishRate"],
advConfirmTime: allData[i]["advertiser"]["advConfirmTime"],
payTypes: payTypesz,
position: 0,
};
finalData.push(obj);
}
console.log(finalData);
} catch (e) {
console.log(e);
}
});
});
exports.scheduledFunction = functions.pubsub
.schedule("* * * * *")
.onRun((context: any) => {
req.write(stringData);
req.end();
for (let i = 0; i < finalData.length; i++) {
database.doc("/$i")
.set({
"tradeType": finalData[i]["tradeType"],
"asset": finalData[i]["asset"],
"fiatUnit": finalData[i]["fiatUnit"],
"price": finalData[i]["price"],
"surplusAmount": finalData[i]["surplusAmount"],
"maxSingleTransAmount": finalData[i]["maxSingleTransAmount"],
"minSingleTransAmount": finalData[i]["minSingleTransAmount"],
"nickName": finalData[i]["nickName"],
"monthOrderCount": finalData[i]["monthOrderCount"],
"monthFinishRate": finalData[i]["monthFinishRate"],
"advConfirmTime": finalData[i]["advConfirmTime"],
"payTypes": finalData[i]["payTypes"],
"position": finalData[i]["position"],
});
}
return console.log("Succes Upload of the data ");
});
// # sourceMappingURL=index.js.map
This is the setup of the DB.
By default https for Node.js does not return Promises, therefore it can be cumbersome to correctly manage the life cycle of your Cloud Function.
I would suggest you use the axios library and refactor your code as follows, using a batched write to write to Firestore:
exports.scheduledFunction = functions.pubsub
.schedule("* * * * *")
.onRun(async (context: any) => { // <=== See async keyword here
try {
const httpCallResponse = await axios.get(...); // I let you adapt the code, including the URL to call, according to the axios doc
const finalData = ... // Again, it's up to you to work out the value based on httpCallResponse
const batch = database.batch();
for (let i = 0; i < finalData.length; i++) {
batch.set(database.doc(i.toString(10)),
{
"tradeType": finalData[i]["tradeType"],
"asset": finalData[i]["asset"],
"fiatUnit": finalData[i]["fiatUnit"],
"price": finalData[i]["price"],
"surplusAmount": finalData[i]["surplusAmount"],
"maxSingleTransAmount": finalData[i]["maxSingleTransAmount"],
"minSingleTransAmount": finalData[i]["minSingleTransAmount"],
"nickName": finalData[i]["nickName"],
"monthOrderCount": finalData[i]["monthOrderCount"],
"monthFinishRate": finalData[i]["monthFinishRate"],
"advConfirmTime": finalData[i]["advConfirmTime"],
"payTypes": finalData[i]["payTypes"],
"position": finalData[i]["position"],
});
}
await batch.commit();
console.log("Succes Upload of the data ");
return null;
} catch (error) {
console.log(error);
return true;
}
});
Extra Note: Note that with your code you create monotonically increasing IDs and that could be a problem.
await mongodb.connect(process.env.MongoUrl , async (err, c)=>
{
if(err){console.log(err)}
var GetData = c.db("Data").collection("Servers")
const Server = await GetData.findOne({IdServer:id}).then(r => {return r})
if(Server != null)
{
return callback(Server.prefix)
}
else
{
GetData.insertOne({IdServer:id,Sersial:false,JoinServerHistory:new Date().toLocaleDateString(),History:"-",prefix:"-",caunt:50})
return callback("")
}
})
}
const Prfix = GetPrfix("9273490839208409" , (r) => {console.log(r)})
/////// ^<<<<<<<< take "r" and and Put in a variable <<<<<<<< ^
The best way is to declare it first, then assign it the value:
var newVar = null;
await mongodb.connect(process.env.MongoUrl , async (err, c)=>
{
if(err){console.log(err)}
var GetData = c.db("Data").collection("Servers")
const Server = await GetData.findOne({IdServer:id}).then(r => {newVar = r;}) // Right here is the magic
// ... SOME MORE CODE
})
}
// You can use `newVar` here as `r`.
I have the following code that I can´t figure out how to make this entire process finish before sending a response back to the client. It has a for loop and make the requests to 2 external functions.
The problem that I can see in the console is the response which goes way faster than the process takes to complete the processing. It makes the client believe everything is fine, but, actually some error might has happened. I´ve tried to await, I´ve tried reading other posts, I´ve tried making this to return a promise and return a resolve, I´ve tried an index to check the array length... If someone could help me out, I would appreciate that. Thanks in advance.
var updateProdCharTree = async (req, res, next) => {
return new Promise((resolve, reject) => {
var data = req.body.raw.data;
var productLine = req.body.raw.productLine;
var bu = req.body.raw.bu;
let contErros = null;
let contAcertos = 0;
var maxId = 0;
let queryMaxId = `SELECT max(ProductCharFatherId) as maxId FROM maxiplastmatriz.productchar1 WHERE bu=${bu} and prodline=${productLine}`;
database.query(queryMaxId)
.then(resultqueryMaxId => {
if(resultqueryMaxId.length){
maxId = resultqueryMaxId[0]['maxId'];
}else{
maxId = 0;
}
let queryAllNodes = `SELECT Id FROM productchar1 WHERE bu=${bu} and prodline=${productLine}`;
database.query(queryAllNodes)
.then( async resultqueryAllNodes => {
for (let index = 0; index < data.children.length; index++) {
const element = data.children[index];
if (data.children[index].dbId != undefined) {
let query = `SELECT Id FROM productchar1 WHERE bu=${bu} and prodline=${productLine} and Id=${data.children[index].dbId} and ProductCharFatherId=${data.children[index].id}`;
database.query(query)
.then( async result => {
if (result.length) { // Update char in productchar1
maxId++;
var params = {element: element, productLine: productLine, bu: bu, index: index};
waitResUp = await updateProductChar1(params, req, res); //***CALL EXTERNAL METHOD 2***
contAcertos++;
} else { // Add char in productchar1 shouldn´t get in here
console.log("Erro em: updateProdCharTree > addProductProductChar1");
}
})
.catch(err => {
console.log("Erro em query");
contErros = 1;
})
}else{ // Add new char in productchar1
maxId++;
var params = {element: element, productLine: productLine, bu: bu, index: index, maxId: maxId};
waitRes = await addProductProductChar1(params, req, res); //***CALL EXTERNAL METHOD 2***
console.log("waitRes", waitRes.insertId);
contAcertos++;
}
}
})
.catch(err => {
console.log("Erro em queryAllNodes", err);
contErros = 1;
})
})
.catch(err => {
console.log("Erro em queryMaxId");
contErros = 1;
});
if (contAcertos == data.children.length) {
resolve("result"); // ***RES ATTEMPT***
}
})
}
Beginner here. Please be pacient. You were once either.
For starters, you can refactor your code to something like below so that response is returned after all async functions within loop are executed:
var updateProdCharTree = async (req, res, next) => {
return new Promise((resolve, reject) => {
var data = req.body.raw.data;
var productLine = req.body.raw.productLine;
var bu = req.body.raw.bu;
let contErros = null;
let contAcertos = 0;
var maxId = 0;
let queryMaxId = `SELECT max(ProductCharFatherId) as maxId FROM maxiplastmatriz.productchar1 WHERE bu=${bu} and prodline=${productLine}`;
database
.query(queryMaxId)
.then((resultqueryMaxId) => {
if (resultqueryMaxId.length) {
maxId = resultqueryMaxId[0]["maxId"];
} else {
maxId = 0;
}
let queryAllNodes = `SELECT Id FROM productchar1 WHERE bu=${bu} and prodline=${productLine}`;
database
.query(queryAllNodes)
.then(async (resultqueryAllNodes) => {
return Promise.all(
data.chilren.map(async (element) => {
if (data.children[index].dbId != undefined) {
let query = `SELECT Id FROM productchar1 WHERE bu=${bu} and prodline=${productLine} and Id=${data.children[index].dbId} and ProductCharFatherId=${data.children[index].id}`;
let result = await database.query(query);
if (result.length) {
// Update char in productchar1
maxId++;
var params = {
element: element,
productLine: productLine,
bu: bu,
index: index,
};
waitResUp = await updateProductChar1(params, req, res); //***CALL EXTERNAL METHOD 2***
contAcertos++;
} else {
// Add char in productchar1 shouldn´t get in here
console.log(
"Erro em: updateProdCharTree > addProductProductChar1"
);
}
} else {
// Add new char in productchar1
maxId++;
var params = {
element: element,
productLine: productLine,
bu: bu,
index: index,
maxId: maxId,
};
waitRes = await addProductProductChar1(params, req, res); //***CALL EXTERNAL METHOD 2***
console.log("waitRes", waitRes.insertId);
contAcertos++;
}
})
);
})
.then(() => {
// This will be called after all queries are executed
resolve("result");
})
.catch((err) => {
console.log("Erro em queryAllNodes", err);
contErros = 1;
// NOTE: Ideally we should be rejecting promise in case of error
});
})
.catch((err) => {
console.log("Erro em queryMaxId");
contErros = 1;
// NOTE: Ideally we should be rejecting promise in case of error
});
});
};
As #Jeremy Thille suggested this code can be improvised further to only use async-await instead of Promises with then callback so that it is more cleaner and easy to understand.
Update multiple rows , is using a bulk update a good solution or something like the code below works ? . I supposed wanted to update all the records with the id and filename.
I did try to update inside a loop but the migration hang up and take too long in this block. is it because of the iterations ? or is there something wrong with the update syntax?. Thank you.
#Code
for (let i = 0; i < documents.length; i++) {
const prefix = Date.now().toString();
const fileParts = documents[i].filename.split('.');
const finalname = `${fileParts[0]}-${prefix}.${fileParts[1]}`;
// eslint-disable-next-line no-await-in-loop
await queryInterface.sequelize.query(`UPDATE ${EmployeeDocumentsModel.tableName} SET filename='${finalname}' WHERE id=${documents[i].id};`, { transaction });
}
#CODE
module.exports = {
up: async (queryInterface) => {
const transaction = await queryInterface.sequelize.transaction();
try {
const sequelizeClient = app.get('sequelizeClient');
const documents = await sequelizeClient.query(
`SELECT id, filename, COUNT(filename) FROM ${EmployeeDocumentsModel.tableName} GROUP BY filename
HAVING COUNT(filename) > 1;`,
{ type: QueryTypes.SELECT },
);
// eslint-disable-next-line no-plusplus
for (let i = 0; i < documents.length; i++) {
const prefix = Date.now().toString();
const fileParts = documents[i].filename.split('.');
const finalname = `${fileParts[0]}-${prefix}.${fileParts[1]}`;
// eslint-disable-next-line no-await-in-loop
await queryInterface.sequelize.query(`UPDATE ${EmployeeDocumentsModel.tableName} SET filename='${finalname}' WHERE id=${documents[i].id};`, { transaction });
}
// eslint-disable-next-line no-unused-vars
// const file = await sequelizeClient.query(
// `DELETE d1 from ${EmployeeDocumentsModel.tableName} d1 inner join ${EmployeeDocumentsModel.tableName} d2 on d2.id < d1.id and d2.filename = d1.filename and d2.employeeId = d1.employeeId`,
// { type: QueryTypes.DELETE },
// );
await queryInterface.addConstraint(EmployeeDocumentsModel.tableName, ['employeeId', 'filename'], {
type: 'unique',
name: 'composite_employee_filename',
}, {
transaction,
});
await transaction.commit();
} catch (err) {
// eslint-disable-next-line no-console
console.log(err);
await transaction.rollback();
throw err;
}
return true;
},
I think the biggest issue is that each update is waiting on the previous to complete:
for (let i = 0; i < documents.length; i++) {
// ...
await queryInterface.sequelize.query(`UPDATE ${EmployeeDocumentsModel.tableName} SET filename='${finalname}' WHERE id=${documents[i].id};`, { transaction });
}
If you change it to:
const promises = [];
for (let i = 0; i < documents.length; i++) {
// ...
promises.push(queryInterface.sequelize.query(`UPDATE ${EmployeeDocumentsModel.tableName} SET filename='${finalname}' WHERE id=${documents[i].id};`, { transaction }));
}
await Promise.all(promises);
you should see a big speedup.
I have a row with value like this below:
{
"id": 1,
"token": "abcd"
}
How do I delete and save the value without "token" so it becomes this?
{
"id": 1
}
Do I need to first get the object, modify it then save back?
Maybe this will help you:
function patch(db, id, delta) {
return new Promise((resolve, reject) => {
const tx = db.transaction('mystore', 'readwrite');
tx.onerror = (event) => reject(event.target.error);
tx.oncomplete = () => resolve();
const store = tx.objectStore('mystore');
const request = store.get(id);
request.onsuccess = (event) => {
const object = event.target.result;
if (!object) {
reject(new Error(`No matching object for ${id}`));
return;
}
for (const prop in delta) {
if (typeof delta[prop] === 'undefined') {
delete object[prop];
} else {
object[prop] = delta[prop];
}
}
store.put(object);
};
});
}
async function dostuff() {
let db;
const id = 1;
const delta = {
token: undefined
};
try {
db = await connect();
await patch(db, id, delta);
} finally {
if (db) {
db.close();
}
}
}