I referred this stack overflow solution but still this did not help me.
I have a find method that works perfectly inside a controller but it does not work inside a async function.
Below is the cron job where i am calling this fuction inside my server.js:
// this performs the job everyday at 10:00 am
cron.schedule("00 10 * * *",async function () {
await notifyBookDefaulties();
});
Below i my async function:
const notifyBookDefaulties = async () => {
console.log("Start");
const getList = async () => {
console.log("Fetching");
const books = await Book.find({"users.dueDate": { $lt: new Date().toISOString() }});
console.log(books);
console.log("Fetched");
};
try {
getList();
console.log("completed");
} catch (error) {
console.log(error);
}
console.log("End");
};
After execution i see the following output in my console:
Start
Fetching
completed
End
and i get the same output if i do const books = await Book.find({});
and if i use await getList() then i get the following output in my console:
Start
Fetching
and if i put a try/catch around const books = await Book.find({"users.dueDate": { $lt: new Date().toISOString() }}); there is no error generated nor any output.
and if i remove const books = await Book.find({"users.dueDate": { $lt: new Date().toISOString() }}) then i see the foolowing in my console
Start
Fetching
Fetched
completed
End
Below is my controller that works correctly and fetches the desired documents:
const dueBooks = async (req, res) => {
const result = await Book.find({"users.dueDate": { $lt: new Date().toISOString() }});
res.status(200).json(result[0]);
};
I tried to few things but it did work. Thanks in advance.
There appear to be two problems. One is you don't instantiate your MongoDB connection when you run your cron like your controller does.
In addition to that, you should be using the await on your getList since you need to wait for that promise inside the try / catch block.
Related
I'm newer to JavaScript and struggling to understand why this function just returns right away, even though I added an await. The code below is the minimal example to replicate what I am attempting to do. When I call add_user() from add(), id is undefined because add_user() is returning right away instead of waiting for completion of the query. I added the console log to verify that row.id is the value I expected (i.e. 1).
'use strict';
import sqlite3 from 'sqlite3'
import { open } from 'sqlite';
async function add_user(value) {
await (async () => {
const db = await open({
filename: dbFile,
driver: sqlite3.Database
})
const row = await db.get(`SELECT id FROM Users WHERE name LIKE "${value}"`)
console.log(row.id)
return row.id
})()
}
async function add(req, res) {
var id = await add_value(req.body.value)
console.log(id)
}
I'm pretty sure the code is running asynchronously as desired - it's just that you aren't returning anything from add_user. For a smaller example:
async function someFn() {
await somePromise;
}
Above, someFn will always return a Promise that resolves to undefined, because nothing was returned from someFn. You're running into the same issue.
Use instead
async function add_user(value) {
const db = await open({
filename: dbFile,
driver: sqlite3.Database
})
const row = await db.get(`SELECT id FROM Users WHERE name LIKE "${value}"`)
console.log(row.id)
return row.id
}
I am trying to execute the following code, however "// go do something else" keeps happening before "// do stuff with things"
It appears that my code is not waiting for mongoose.model('things').find() to finish before moving on. I've tried different variations of async/await and nothing seems to work.
Not getting errors an everything executes, just out of order.
const asyncFunction = async () => {
mongoose.connect(`mongodb+srv://...`);
mongoose.model('things', {data:String});
mongoose.model('things').find((err, things)=>{
// do stuff with things
}
console.log('something');
}
const otherAsyncFunction = async () {
await asyncFunction();
// go do something else
}
otherAsyncFunction();
Your asyncFunction doesn't return anything, so there's no point awaiting it.
You have no Mongoose schema.
The syntax to create a Mongoose model (doc) is :
const thingsShema = new mongoose.Schema({ data: 'string' });
const Thing = mongoose.model('thing', thingsShema );
You are creating your model, but then your model isn't stored in a variable and you're not using it at all.
mongoose.model('things') : this line creates a new Mongoose model but you're not passing it any schema. Anyway you already did that on the previous line.
.find() is asynchronous, and you're not returning its value.
You aren't passing any argument to .find(), only a callback function.
This code should work better :
const asyncFunction = async () => {
await mongoose.connect(`mongodb+srv://...`);
const thingsSchema = new mongoose.Schema({ data: 'string' });
const Things = mongoose.model('things', thingsSchema);
const foundThings = await Things
.find({}) // Query conditions (here, querying for 'everything', an empty object)
.lean() // Returns simple JSON and not a collection of Mongoose objects
.exec(); // returns a true Promise and not just a thenable
console.log('foundThings = ', foundThings);
return foundThings; // this returns a Promise, because 'async' functions always do
}
const otherAsyncFunction = async () => {
const result = await asyncFunction();
console.log("Result = ", result); // Normally this will log the same thing as 'foundThings'
// go do something else
}
otherAsyncFunction();
async functions return Promise object. When you exec await asyncFunction(), 'await' wait status asyncFunction() - resolve or reject.But in your code there are no resolve() or reject() functions. So you need to do like this:
const asyncFunction = async (resolve) => {
mongoose.connect(`mongodb+srv://...`);
mongoose.model('things', {data:String});
mongoose.model('things').find((err, things)=>{
// do stuff with things
});
console.log('something');
resolve()
}
const otherAsyncFunction = async () => {
await asyncFunction();
// go do something else
}
otherAsyncFunction();
I'm trying to build a simple REST API using Express.js, first time using it.
So I run the Express application generator using npx express-generator. Then, on /routes/users.js, I add a get method to retrieve data from an MSSQL database with the following code:
router.get('/api/v1/test', (req, res) => {
(async () => {
try {
let pool = await sql.connect(dbConfig);
let result1 = await pool.request().query('select * from andromedadb.dbo.test');
console.dir(result1);
} catch (err) {
console.log('err', err);
}
})();
});
I know the connection is successful because the console prints the following:
{
recordsets: [ [ [Object] ] ],
recordset: [ { id: 1, name: 'hello', age: 17 } ],
output: {},
rowsAffected: [ 1 ]
}
My issue is that the browser tab keeps loading and executing the get method over and over.
I also tried the code snippet on https://www.js-tutorials.com/nodejs-tutorial/simple-example-of-nodejs-express-with-mssql/#Listing_Nodejs_MSSQL_Using_Express, but the very same thing was happening.
Thanks in advance.
You need to send the response back to the request. I just modified your code, Look at the changes in the below code.
router.get('/api/v1/test', (req, res) => {
(async () => {
try {
let pool = await sql.connect(dbConfig);
let result1 = await pool.request().query('select * from andromedadb.dbo.test');
console.dir(result1);
res.status(200).send(result1);
} catch (err) {
res.status(401).send(err);
console.log('err', err);
}
})();
});
You need to send back some response with your res object or call the next() function to go into your next middleware, otherwise you are just leaving your request hanging, thus the infinite load. Add a res.send() or res.json() function to mark the end of your function.
router.get('/api/v1/test', (req, res) => {
(async () => {
try {
let pool = await sql.connect(dbConfig);
let result1 = await pool.request().query('select * from andromedadb.dbo.test');
console.dir(result1);
res.status(200).send("Received the response successfully");
} catch (err) {
console.log('err', err);
res.status(500).send("Something went wrong");
}
})();
});
How are you calling the route from the front end application?
As you are using an async function for your get method, remember to use 'await':
const response = await getRecordSet();
// do stuff with 'response'
I am uploading an initial data to firebase-firestore. The data is to be used as a fixture to develop my frontend further. I do not have errors, at least haven't caught one yet. The following two functions, are being used to upload data:
Edited to explain better
async function uploadData() {
const userId = 'AKFROjo1isTPRfjYYDsSehwZdIi1';
const itemsListRef = await db.collection('users').doc(userId).collection('userData').doc('itemsList');
await itemsListRef.set({ created: firebase.firestore.FieldValue.serverTimestamp() });
await summaryList.forEach(async summary => {
await itemsListRef.collection('summaryList').add(summary);
});
await coreCompetencyList.forEach(async coreCompetency => {
await itemsListRef.collection('coreCompetencyList').add(coreCompetency);
});
}
and a second function as -
async function uploadData2() {
const userId = 'AKFROjo1isTPRfjYYDsSehwZdIi1';
const itemsListRef = await db.collection('users').doc(userId).collection('userData').doc('itemsList');
await itemsListRef.set({ created: firebase.firestore.FieldValue.serverTimestamp() });
await educationList.forEach(async education => {
await itemsListRef.collection('educationList').add(education);
});
await categoryList.forEach(async category => {
await itemsListRef.collection('categoryList').add(category);
});
}
It is being called as :
async function main() {
try {
await uploadData();
await app.delete();
} catch (e) {
console.log('Data upload failed, reason:', e, '\n\n');
}
}
main().then(r => console.log('Done.'));
I am surprised that I cannot put all 4 calls in a single function
It's not a bug. This is the way it was intended to work.
In actuality, collections are not really entities that require creation or deletion like folders in a filesystem. They are just virtual containers for documents that spring into existence immediately when the first document in created under it, and automatically disappear when the last document in deleted. You can think of them more like units of organization that make indexing and security rules possible to implement.
My Firestore data model looks like this
Organizations/{orgId}/cloudAccounts/{cloudAccountId}/resources/{resourceId}
I am running a simple query like this
let documents = await db.collection("Organizations")
.doc("orgIdabc")
.collection("cloudAccounts")
.doc("cloudAccountIdabc")
.collection("resources")
.get();
console.log("LENGTH: ", documents.docs.length);
Now the problem is that when I try to log the document length, it's always giving me a different length. I'll share the output as well.
LENGTH: 18
LENGTH: 19
LENGTH: 19
LENGTH: 6
LENGTH: 3
LENGTH: 19
LENGTH: 12
LENGTH: 19
LENGTH: 19
Now the actual length is 19, but as you can see I am getting different lengths.
I've no idea what's the problem here, any help would be really appreciated.
Updated
as per request I am adding the complete code snippet
Also I've come to know that this problem is only happening on Admin SDK and not the client SDK
const { db } = require("./firestore");
const functions = require("firebase-functions");
exports.runScanOnAllCloudAccounts = functions.https.onRequest((req, res) => {
runScanOnAllCA();
return res.status(200);
});
async function runScanOnAllCA() {
try {
for (let i = 0; i < 10; i++) {
let documents = await db.collection("Organizations")
.doc("orgIdabc")
.collection("cloudAccounts")
.doc("cloudAccountIdabc")
.collection("resources")
.get();
console.log("LENGTH: ", documents.docs.length);
}
} catch (err) {
console.log("err: ", err);
}
}
Update 02 ===========>
I've updated the code to use Promise() heavy approach, as recommended by some users and I still get different document lengths.
I feel that people are missing the point here, Promises are just a way to run asynchronous code, we can resolve this by using async await that was already being used in the previous version of the code.
Still the following code snippet doesn't solve the problem.
const { db } = require("./firestore");
const functions = require("firebase-functions");
exports.runScanOnAllCloudAccounts = functions.https.onRequest(
async (req, res) => {
runScanOnAllCA(res)
.then(resolve => {
console.log(resolve);
})
.catch(err => {
console.log(err);
});
// return res.status(200);
}
);
async function runScanOnAllCA(res) {
return new Promise(async (resolve, reject) => {
db.collection("Organizations")
.doc("sumair-hello-world_axtr8")
.collection("cloudAccounts")
.doc("4ZQgjt94pvEQTlvxSJ75")
.collection("resources")
.get()
.then(querySnapshot => {
resolve(querySnapshot.docs.length);
})
.catch(err => {
reject(err);
});
});
}
You should use the Admin SDK in order to interact with Firestore from a Cloud Function.
Secondly, it is known that using await in loops can lead to "erratic" results. See, for example, https://www.google.com/search?client=firefox-b-d&q=for+and+await
Finally, note that you are incorrectly calling your asynchronous runScanOnAllCA() function. You should either use then() or make your Cloud Function async and use await, see the code below.
You should adapt your CF as follows for using the Admin SDK:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.runScanOnAllCloudAccounts = functions.https.onRequest(async (req, res) => {
await runScanOnAllCA(); //<--- Note the await here and the async above, since you are calling an async function
res.status(200); //<--- No need to use return in an HTTPS Cloud Function, just terminate it with res.redirect(), res.send(), or res.end().
});
async function runScanOnAllCA() {
try {
const db = admin.firestore();
//The loop was removed. Use another way if needed, e.g. Promise.all() or the techniques presented in the links above.
let documents = await db.collection("Organizations")
.doc("orgIdabc")
.collection("cloudAccounts")
.doc("cloudAccountIdabc")
.collection("resources")
.get();
console.log("LENGTH: ", documents.docs.length);
} catch (err) {
console.log("err: ", err);
}
}