Inside foreach loop, the await is not working - asynchronous

Below this code downloadcontroller.js
// Retrieve all downloads from the database.
exports.findAll = async (req, res) => {
downloadObj
.findAll(
{
include: [
{
model: composerObj,
required: false,
},
{
model: raagaObj,
required: false,
},
{
model: taalaObj,
required: false,
},
],
where: req.query,
raw:true,
nest: true,
})
.then((data) => {
data.forEach(async (element) => {
const artistsArray = [];
let whereConstraint = {};
JSON.parse(element.artists).forEach( async (ele) => {
artistsArray.push(ele.artistId);
});;
whereConstraint = {
id : {
[Op.in]: artistsArray
}
}
element.Active = "true11";
const artistData = artistService.customfindAll(whereConstraint);
element.artistData = artistData;
console.log("artistData",artistData);
});
console.log("data",data);
console.log("3");
res.status(200).send({
status:200,
message: "ok",
data:data
});
console.log("4");
})
.catch((err) => {
res.status(500).send({
status:500,
message:
err.message || "Some error occurred while retrieving Download.",
});
});
};
Below this code, artistServer.js file
exports.customfindAll = async (whereConstraint) => {
return new Promise(function(resolve, reject) {
artistObj
.findAll({
attributes:{
include: [
[fn('IF',literal('imagePath!=""'),(fn('CONCAT', artistImagePath, 'artist/', col('imagePath'))),artistImageDefaultPath), 'imageFullPath'],
],
},
where: whereConstraint,
order: [
['artistName', 'ASC'],
],
raw:true,
nest: true,
})
.then((data) => {
resolve(data);
});
});
}
Here my problem is
const artistData = artistService.customfindAll(whereConstraint);
not waiting for the data. .So that I got the result, below have mentioned. Actually the artistData attribute column, need result data.
{
"status": 200,
"message": "ok",
"data": [
{
"id": 1,
"fileType": "1",
"customFileName": "test filename",
"artists": "[{\"artistId\":1},{\"artistId\":4},{\"artistId\":2}]",
"accompanyingArtists": "[{\"instrumentId\":1,\"accompanyingArtistId\":1},{\"instrumentId\":2,\"accompanyingArtistId\":6},{\"instrumentId\":3,\"accompanyingArtistId\":4}]",
"Active": "true11",
"artistData": {}
},
{
"id": 2,
"fileType": "1",
"customFileName": "new file name",
"artists": "[{\"artistId\":1},{\"artistId\":4},{\"artistId\":2},{\"artistId\":6},{\"artistId\":3}]",
"accompanyingArtists": "[{\"instrumentId\":1,\"accompanyingArtistId\":1},{\"instrumentId\":2,\"accompanyingArtistId\":6},{\"instrumentId\":3,\"accompanyingArtistId\":4},{\"instrumentId\":3,\"accompanyingArtistId\":3},{\"instrumentId\":4,\"accompanyingArtistId\":2}]",
"Active": "true11",
"artistData": {}
}
]
}
In console page, I artistdata attribute pending...
enter image description here

The customFindAll function returns a Promise but the forEach does not wait for it. Add an await:
const artistData = await artistService.customfindAll(whereConstraint);
Also, forEach does not wait, it just fires off the async functions and move on. To wait for the forEach to finish, you need a map and a Promise.all, like this:
await Promise.all(data.map(async (element) => {
const artistsArray = [];
let whereConstraint = {};
JSON.parse(element.artists).forEach( async (ele) => {
artistsArray.push(ele.artistId);
});;
whereConstraint = {
id : {
[Op.in]: artistsArray
}
}
element.Active = "true11";
const artistData = await artistService.customfindAll(whereConstraint);
element.artistData = artistData;
console.log("artistData",artistData);
}));
The way it works this way is that data.forEach(async (e) => ... runs the async function and discards the results (the Promises). If you use a map, like data.map(async (e) => ..., you'll get an array of Promises, then use await Promise.all(...) to wait for them.

Related

Accessing URL to use issues (expo/react native app/firebase)

In my current app i want the user to pick a photo from their phone and then to use the downloadable url from firebase storage to then add it to my database. Everything works but when a user(when they first time to pick a image) it says
TypeError: Network request failed
code(logic/state/functions):
const [image, setImage] = useState(null);
const [url, setUrl] = useState(null)
async function postImage () {
try {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled) {
imgFirebase()
setImage(result.assets[0].uri); }
}
catch(E) {
Alert.alert(
"Alert Title",
"My Alert Msg 1",
[
{
text: "Cancel",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "OK", onPress: () => console.log("OK Pressed") }
]
);
}
}
async function imgFirebase () {
try {
console.log(image);
const d = await fetch(image)
const dd = await d.blob()
const fileName = image.substring(image.lastIndexOf("/")+1)
const storage = getStorage();
const storageRef = ref(storage, fileName);
uploadBytes(storageRef,dd).then((snapshot) => {
getDownloadURL(snapshot.ref).then(async (url) => {
// Create a query against the collection.
setUrl(url)
console.log(url)
}).catch(e=>{
Alert.alert(
"Alert Title",
"My Alert Msg 2",
[
{
text: "Cancel",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "OK", onPress: () => console.log("OK Pressed") }
]
);
})
});
}
catch(e) {
alert(e)
}
}
code(for rendered UI):
<Pressable color="#000" style={{marginTop:20,backgroundColor:"#FF35F0",padding:10,borderRadius:11,color:"#000"}} onPress={postImage}>
<Text style={{color:"#fff",textAlign:"center",fontSize:20}}>Pick Image</Text>
</Pressable>
whats also weird is that after the first time getting this error and then trying to pick a image the error finally goes away. Why does this error come up at first? How would i fix this?

How to mutation store state in build query redux toolkit

Created an initialState and will be updated the totalPage and currentPage after got the users list.
I found out onQueryStarted from docs, it able to update the store state in this method but only look like only for builder.mutation.
what's the correct way to get the user list and update the store page value in redux toolkit?
Listing two part of the code below:
apiSlice
component to use the hook
// 1. apiSlice
const usersAdapter = createEntityAdapter({})
export const initialState = usersAdapter.getInitialState({
totalPage: 0,
currentPage: 0,
})
export const usersApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUsers: builder.query({ // <--- the docs are using builder.mutation, but i needed to pass params
query: (args) => {
const { page, limit } = args;
return {
url: `/api/users`,
method: "GET",
params: { page, limit },
}
},
validateStatus: (response, result) => {
return response.status === 200 && !result.isError
},
transformResponse: (responseData) => { // <<-- return { totalPages: 10, currentPage: 1, users: [{}] }
const loadedUsers = responseData?.users.map((user) => user)
return usersAdapter.setAll(initialState, loadedUsers)
},
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled
const {totalPages, currentPage} = data; <----- totalPages & currentPage values are still 0 as initialState
dispatch(setPages({ currentPage, totalPages }))
} catch (error) {
console.error("User Error: ", error)
}
},
providesTags: (result, error, arg) => {
if (result?.ids) {
return [
{ type: "User", id: "LIST" },
...result.ids.map((id) => ({ type: "User", id })),
]
} else return [{ type: "User", id: "LIST" }]
},
})
})
});
export const {
useGetUsersQuery,
} = usersApiSlice
component to use the hook
Try to use the hook in user landing page
const UsersList = () => {
const { data: users, isLoading, isSuccess, isError } = useGetUsersQuery({page: 1, limit: 10 })
return (
<div>return the users data</div>
)
}
update the store value after get the data return

Firebase get request querying multiple tables

I'm trying to send get request to get the information of a row and that of its comments and options (rows, comments, options are all different tables). Currently, the request returns the row and comment info, but an empty array for the options, like so:
{
"categoryId": "Category1",
"dataType": "Text",
"approveCount": 0,
"createdAt": "10:00",
"body": "testneww",
"disapproveCount": 0,
"index": 1,
"visit": "Both",
"rowId": "ID",
"comments": [
{
"rowId": "ID",
"createdAt": "2021-02-28T21:32:52.841Z",
"body": "test comment"
}
],
"options": []
}
code:
exports.getOneRow = (req, res) => {
let rowData = {};
db.doc(`/rows/${req.params.rowId}`)
.get()
.then((doc) => {
if (!doc.exists) {
return res.status(404).json({ error: 'Row not found' });
}
rowData = doc.data();
rowData.rowId = doc.id;
return db
.collection('comments')
.orderBy('createdAt', 'desc')
.where('rowId', '==', req.params.rowId)
.get();
})
.then((data) => {
rowData.comments = [];
data.forEach((doc) => {
rowData.comments.push(doc.data());
})
return db
.collection('options')
.orderBy('index', 'asc')
.where('rowId', '==', req.params.rowId)
.get();
})
.then((newData)=>{
rowData.options = [];
newData.forEach((newDoc) => {
rowData.options.push(newDoc.data());
})
return res.json(rowData);
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: err.code });
});
};
I presume I'm making a silly mistake somwhere, or is it not possible to do a request like this? Any help appreciated!
The following code worked, I cant see any differences besides adding the parameters individually in 'rowData.options.push' near the end, however ive been staring at the same code for quite a while so please do let me know if im missing something else.
exports.getOneRow = (req, res) => {
let rowData = {};
db.doc(`/rows/${req.params.rowId}`)
.get()
.then((doc) => {
if (doc.exists) {
rowData = doc.data();
rowData.rowId = doc.id
return db
.collection("comments")
.where("rowId", "==", req.params.rowId)
.get();
} else{
return res.status(500).json({ error: err.code });
}
})
.then((data) => {
rowData.comments = [];
data.forEach((doc) => {
rowData.comments.push(doc.data());
});
return db
.collection("options")
.where("rowId", "==", req.params.rowId)
.orderBy("index", "asc")
.get();
})
.then((data) => {
rowData.options = [];
data.forEach((doc) => {
rowData.options.push({
index: doc.data().index,
body: doc.data().body,
rowId: doc.data().rowId,
});
});
return res.json(rowData);
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};

Action call is returning 'undefined' with fetch-mock

Action "type": undefined, is what I keep getting returned when I try to test a redux action with fetch-mock. Any suggestion on how to resolve this issue? Could it be a bug in fetch-mock?
Expected value to equal:
[{"type": undefined}, {"result": {"hello": "world"}, "type": undefined}]
Received:
[{"type": "DASHBOARD_RESULT_LOADING"}, {"result": {"hello": "world"}, "type": "DASHBOARD_RESULT_READY"}]
dashboardActions.js
function resultReady(json) {
return {
type: DASHBOARD_RESULT_READY,
result: camelizeKeys(json)
};
}
export function requestPredict(params) {
let url = `${process.env.API_URL}/predict/`;
const requestParams = {
method: 'post',
credentials: 'include'
};
return async (dispatch) => {
return fetch(url, requestParams)
.then(response => {
if (response.status === 200) {
return response.json();
} else {
throw Error(response.statusText);
}
})
.then(data => dispatch(resultReady(data)));
};
}
dashboardActions.test.js
const mockData = {
"hello": "world"
}
describe('action creators', () => {
afterEach(() => {
fetchMock.reset()
})
it('should create DASHBOARD_RESULT_LOADING', () => {
fetchMock.post('*', {"hello":"world"} );
const expectedActions = [
{ type: actions.DASHBOARD_RESULT_LOADING },
{ type: actions.DASHBOARD_RESULT_READY, result: mockData }
]
const store = mockStore({ result: {}})
return store.dispatch(actions.requestPredict())
.then((data) => {
expect(store.getActions()).toEqual(expectedActions)
})
})
})
You're receiving types "DASHBOARD_RESULT_LOADING" and "DASHBOARD_RESULT_READY", which seems to be the intended behaviour. You're expecting actions.DASHBOARD_RESULT_LOADING and actions.DASHBOARD_RESULT_READY, neither of which seems to be defined with any value.
Either define actions.DASHBOARD_RESULT_LOADING and actions.DASHBOARD_RESULT_READY:
actions.DASHBOARD_RESULT_LOADING = 'DASHBOARD_RESULT_LOADING'
actions.DASHBOARD_RESULT_READY = 'DASHBOARD_RESULT_READY'
or replace them with your expected types:
const expectedActions = [
{
type: 'DASHBOARD_RESULT_LOADING'
},
{
type: 'DASHBOARD_RESULT_READY',
result: mockData
}
]

How to test cyclejs http driver?

Suppose I have an API that return user detail:
/api/get_user/1
{
"status": 200,
"data": {
"username": "username1",
"email": "username#email.com"
}
}
And a "main function" like this:
function main (sources) {
const request$ = sources.ACTIONS
.filter(action => action.type === 'GET_USER_REQUEST')
.map(action => action.payload)
.map(payload => ({
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}))
const action$ = sources.HTTP
.select('GET_USER_REQUEST')
.flatten()
.map(response => response.data)
const sinks = {
HTTP: request$,
LOG: action$
}
return sinks
}
For testing the "ACTION" source, I can simply made an xstream observable
test.cb('Test main function', t => {
const actionStream$ = xs.of({
type: 'GET_USER_REQUEST',
payload: { userId: 1 }
})
const sources = { ACTION: actionStream$ }
const expectedResult = {
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}
main(sources).HTTP.addEventListener({
next: (data) => {
t.deepEqual(data, expectedResult)
},
error: (error) => {
t.fail(error)
},
complete: () => {
t.end()
}
})
})
The question is. Is it possible to do the same thing (using plan xstream observable)
to test cycle-http driver without a helper from something like nock?
Or is there a better way to test something like this?
You can mock out the HTTP source like so:
test.cb('Test main function', t => {
const actionStream$ = xs.of({
type: 'GET_USER_REQUEST',
payload: { userId: 1 }
})
const response$ = xs.of({
data: {
status: 200,
data: {
username: "username1",
email: "username#email.com"
}
}
});
const HTTP = {
select (category) {
// if you have multiple categories you could return different streams depending on the category
return xs.of(response$);
}
}
const sources = { ACTION: actionStream$, HTTP }
const expectedResult = {
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}
main(sources).HTTP.addEventListener({
next: (data) => {
t.deepEqual(data, expectedResult)
},
error: (error) => {
t.fail(error)
},
complete: () => {
t.end()
}
})
})
Really, we should have a mockHTTPSource helper to make this a bit easier. I have opened an issue to that effect. https://github.com/cyclejs/cyclejs/issues/567
If you want to test that certain things happen at the correct time, you could use this pattern in conjunction with #cycle/time.
http://github.com/cyclejs/time

Resources