How to correctly resolve promise in a mongoDB call? - javascript

I am trying to read data from a mongoDB. Ultimately I want the data retrieved from the DB to be in json formate. My currently function goes as:
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true })
const getdata = async (): Promise<string[]> => {
let alldata: string[]
try {
await client.connect()
const database = client.db('data')
const collection = database.collection('datacollection')
const cursor = collection.find({ type: 'featureName' })
alldata = await cursor.toArray()
//console.log(alldata) //This correctly sends the required data to the console.
} finally {
void client.close()
}
//console.log(alldata) //This correctly sends the required data to the console.
return alldata
}
const data = getdata()
console.log(data) // this sends a "Promise { pending }"
I am new to javascript/typescript, but I thought that I was doing all the correct things with an asyc function and the await's -> but that clearly is not the case. Any suggestions as to what I am doing wrong is appreciated.

Your function is returning a Promise so you need to use promise.then.
E.g.
getData().then((data) => {
console.log(data);
});
Take a look at the Promise documentation here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Related

can I await for a state before parsing the data in react?

I have a custom hook that gets file data from the cache api based on an url. The hook works fine.
Problem is that I get a response back and I need to parse this data before I can use the fabric tag picker. and I also only want to parse that data when the user starts typing.
I know that the prop "filterSuggestedTags" accepts a promise like call and we can fetch data before there.
You will see that I am using a fetch inside the filterSuggestedTags and that ensures to fetch the data from the url before showing the results, plus it shows the loader as well:
https://codepen.io/deleite/pen/MWjBMjY?editors=1111
So given the code below and the fact that my useCache gives my a fetch response as state:
const filterSuggestedTags = async (filterText: string, tagList: ITag[]) => {
if (filterText) {
// how can I await the response state? before I can parse the data
return (await /* resp should be the state from the custom hook*/ resp.json()).map(item => ({ key: item.id, name: item.title }));
} else return []
};
Be warned, this is not tested, nor am I of the opinion this the best thing to do, just some thoughts.
EDIT: After some thinking, this might be better
This might save you some headaches with old sate, updates.
const useFilterSuggestedTags = async (filterText: string, tagList: ITag[]) => {
const [data, setData] = useState<WhateverYouReturn[]>([]);
useEffect(() => {
const controller = new AbortController();
if (filterText) fetchData();
async function fetchData() {
try {
const resp = await fetch('url', {signal: controller.signal});
const json = await resp.json();
if (!controller.signal.aborted) {
setData(json.map(_ => ({ key: _.id, name: _.title, })));
}
} catch(e) {
if (!(e instanceof AbortError)) throw e
}
}
// If your effect returns a function, React will run it when it is time to
// clean up:
return controller.abort;
}, [filterText, tagList])
return data;
};
Old Answer
How about
const useFilterSuggestedTags = async (filterText: string, tagList: ITag[]) => {
const [data, setData] = useState<WhateverYouReturn[]>([]);
if (filterText) fetchData();
return data;
async function fetchData() {
const resp = await {}; // Obviously fetch something
const json = await resp.json();
// I assume you also need to filter them, but I guess you know how
// to do that :P
setData(json.map(_ => ({ key: _.id, name: _.title, })));
}
};
Little notice: It is good practice to name your hooks use[...]. At least that is what they (and the react-hooks es-lint plugin) suggest.

Array index returns undefined after push - Papa Parse

I used Papa Parse to parse a .csv file, and pushed the result to an empty array called parsed_data. I am able to use console.log(parsed_data), and view the arrays produced. However, when I try to index the data, for example, console.log(parsed_data[0]), the result is undefined. Not sure what's going wrong here.
Example code:
let parsed_data = [];
const data_url = "acdata.csv";
async function getData() {
const response = await fetch(data_url);
const blob = await response.blob();
const data = Papa.parse(blob, {
complete: function(results) {
//console.log("Finished:", results.data);
parsed_data.push(results.data);
}
});
};
console.log(parsed_data);
getData();
Since Papa parse complete callback is called asynchronously, you'll need to wait for that to complete - however, papa parse doesn't seem to use Promises, so, you can "promisify" the parse function like so
const papaParsePromise = blob => new Promise(resolve => Papa.parse(blob, { complete: resolve }));
Another way of looking at that function, if you don't understand the => notation, is
function papaParsePromise(blob) {
return new Promise(function(resolve) {
Papa.parse(blob, {
complete: function(data) {
resolve(data);
}
);
});
}
that returns a promise that resolves to the data that is passed to the complete callback
Your code would also need to wait for the promise returned by getData before it can use anything in that data. Unless your code is inside another async function, you'll need to use promise .then method, as below
const data_url = "acdata.csv";
async function getData() {
// create a function that returns a Promise that resolves when papa parse complete is called
const papaParsePromise = blob => new Promise(resolve => Papa.parse(blob, { complete: resolve }));
const response = await fetch(data_url);
const blob = await response.blob();
const data = await papaParsePromise(blob);
return data;
};
getData()
.then(parse_data => {
console.log(parsed_data);
console.log(parsed_data[0]);
// i.e. do what you need with parsed_data here
});
if, however, you are calling getData inside an async function - along with the changes to getData above, you can simply use await getData() to wait for the value - i.e.
async function someFunction() {
const parsed_data = await getData();
// do what you need with parsed_data here
}

Return Mongoose query result through multiple methods

I'm trying to retrieve data from a MongoDB database using Mongoose to access the data, however I am trying to retrieve the data through a few methods. Here is my retrieveDocument method:
function retrieveDocument(collectionName, schema, _id) {
conn.once('open', async () => {
var model = mongoose.model(collectionName, schema, collectionName)
return await model.findById(_id)
});
}
and how I'm calling the method:
function retrieveUserDocument(_id){
return retrieveDocument("User", some_Schema, _id);
}
console.log(retrieveUserDocument("some_Id"));
However the result isn't being printed out, and instead the code is logging undefined, as the model.findById(_id) method returns a Promise.
How can I print out the result in the structure I have defined above?
I think you should try promise here. It might work and you should try await when you are calling mongoose model. Try the code which is written below
function retrieveDocument(collectionName, schema, _id) {
return new Promise(async(resolve, reject) => {
conn.once('open', async () => {
var model = await mongoose.model(collectionName, schema, collectionName)
resolve(model.findById(_id))
});
});
}

Async functions using value from a promise

So I know this question is asked a lot, but I'm trying to retrieve a variable that is created within a promise. The examples I've seen on here involve calling .then and using the data there, however what I'm trying to do involves an async function--which i cant use within the .then block.
Here's my code. I'm using the Asana API To call out a lists of tasks that are due. It successfuly logs it. But I want to save the list value from the last block as a variable that I can use elsewhere.
const asana = require('asana');
const client = asana.Client.create().useAccessToken("xxx");
client.users.me()
.then(user => {
const userId = user.id;
// The user's "default" workspace is the first one in the list, though
// any user can have multiple workspaces so you can't always assume this
// is the one you want to work with.
const workspaceId = user.workspaces[0].id;
return client.tasks.findAll({
assignee: userId,
workspace: workspaceId,
completed_since: 'now',
opt_fields: 'id,name,assignee_status,completed'
});
})
.then(response => {
// There may be more pages of data, we could stream or return a promise
// to request those here - for now, let's just return the first page
// of items.
return response.data;
})
.filter(task => {
return task.assignee_status === 'today' ||
task.assignee_status === 'new';
})
.then(list => {
console.log (util.inspect(list, {
colors: true,
depth: null
}));
})
.catch(e => {
console.log(e);
});
If you're open to rewriting your .then()'s as async/await something like this could work for you:
const fetch = require('node-fetch');
async function doit() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const json = await response.json();
console.log(json);
}
doit();

supertest and checking DynamoDB before and after using await

I'd like to test my koa API routes using supertest and check what's in DynamoDB before and after to make sure that the end point did what was intended.
// app related
const pool = require('../../src/common/pool');
const app = require('../../server');
// for testing
const uuid = require('uuid');
const supertest = require('supertest');
// listen on port 40002
const request = supertest.agent(app.listen(4002));
describe('test', () => {
it.only('should', async (done) => {
debugger;
const id = uuid.v4().replace(/-/g, '');
await pool.add(id, 'data', 30);
return request
.get('/api/1')
.expect(204)
// .then(async (res) => {
// .then((res) => {
.end((res) => {
// still returns 'data' instead of 'dataNew' after the route is hit
const record = await pool.get(id);
debugger;
done();
});
});
});
In the code above, I'm creating a record in the db, then I hit the end point, and I tried a then() and an end() chained function to check the db once again. The end point will just data to dataNew and in the then() function, it still returns the original data.
Any ideas on how I can verify the new record in the db ?
References:
Supertest: Verify database after request - In TLDR at the bottom, the solution was to use co. I tried this and had issues probably cause I'm using await instead of generators.
The above was fixed by chaining the pool.add() which returns a promise, to the supertest request and then awaiting the record to verify it. Sometimes it still gets the record too quickly because the pool.update() method is not awaited within the end point that request is hitting.
describe('test', () => {
it.only('should', async () => {
const id = uuid.v4().replace(/-/g, '');
await pool.add(id, 'data', 30).then(() => {
return request
.get('/api/1')
.expect(204)
// check custom headers
//.expect('pool-before', 'data')
//.expect('pool-after', 'dataModified')
.then(async (res) => {
const record = await pool.get(id);
debugger;
expect('dataModified').to.equal(record.fields.S);
});
});
});
});
The only other way I can think of is to check the value via a custom header, a delay, or use a mock.
Let me know if anyone has a better solution.

Categories

Resources