MongooseError: "Query was already executed: .." - reactjs

my function getContents results in the error:"Query was already executed: Content.find({})"
why am i getting this error? how can i fix it? i recently changed this function and this was the byproduct.
exports.getContents = asyncErrors (async (req,res,next) =>{
const contentsCount = await Content.countDocuments(); //162
const resPerPage = 9;
const apiFeatures = new APIFeatures(Content.find(),req.query).search().filter()
console.log(" api " + apiFeatures)
let contents = await apiFeatures.query;
console.log(' contentslist ' + contents)
let filteredContentCount = contents.length;
console.log(' filtered ' + filteredContentCount)
apiFeatures.pagination(resPerPage)
contents = await apiFeatures.query;
/* */
// let cont = await Content.find()
// let cont2 = await Promise.all (cont.map(async (item) =>{
// item.set('content-Count',await Content.find({categories:item._id}).countDocuments(),{strict:false});
// return item
// }))
// console.log(' cont ' + cont2)
/* */
/* check for category request
assign total amount of objects within a category to a variable/constant
if(category.req){
let contentCount = category.counter
}
*/
setTimeout(() => {
res.status(200).json({
success:true,
contentsCount,
resPerPage,
filteredContentCount,
contents
})
}, 2000);
})
I have found that it could be a call back issue with async and await. but i am lost on whether that applies here

Related

How to upload multiple audio file in react but sending only 3 POST request

I want to select 100 audio file at a time but want to hit only 3 api call at a time. Once these 3 files uploaded (pass or fail) then only other 3 api request will be sent.
Basically I am providing a input field of file type:
<input type="file" multiple name="file" className="myform"
onChange={handleFileChange}
accept="audio/wav"
/>
and I am storing it as array into a state.
Below this I am providing an UPLOAD button.
When user hit on upload, I want to send 3 POST request using axios. once all 3 done either fail or pass then only next 3 should go.
You can do this by iterating the FileList collection in groups of 3 and sending the requests in parallel using Promise.allSettled().
Simply because I cannot recommend Axios, here's a version using the Fetch API
const BATCH_SIZE = 3;
const [fileList, setFileList] = useState([]);
const [uploading, setUploading] = useState(false);
const handleFileChange = (e) => {
setFileList(Array.from(e.target.files)); // just a guess
};
const handleUploadClick = async (e) => {
e.preventDefault();
setUploading(true);
const files = [...fileList]; // avoid mutation during long uploading process
for (let i = 0; i < files.length; i += BATCH_SIZE) {
const result = await Promise.allSettled(
files.slice(i, i + BATCH_SIZE).map(async (file) => {
const body = new FormData();
body.append("file", file);
const res = await fetch(UPLOAD_URL, { method: "POST", body });
return res.ok ? res : Promise.reject(res);
})
);
const passed = result.filter(({ status }) => status === "fulfilled");
console.log(
`Batch ${i + 1}: ${
passed.length
} of ${BATCH_SIZE} requests uploaded successfully`
);
}
setUploading(false);
};
Promise.allSettled() will let you continue after each set of 3 are uploaded, whether they pass or fail.
This method makes 3 separate requests with 1 file each.
With Axios, it would look like this (just replacing the for loop)
for (let i = 0; i < files.length; i += BATCH_SIZE) {
const result = await Promise.allSettled(
files
.slice(i, i + BATCH_SIZE)
.map((file) => axios.postForm(UPLOAD_URL, { file }))
);
const passed = result.filter(({ status }) => status === "fulfilled");
console.log(
`Batch ${i + 1}: ${
passed.length
} of ${BATCH_SIZE} requests uploaded successfully`
);
}
Axios' postForm() method is available from v1.0.0. See https://github.com/axios/axios#files-posting
If you want to send 3 files in a single request, it would look like this for Fetch
for (let i = 0; i < files.length; i += BATCH_SIZE) {
const body = new FormData();
files.slice(i, i + BATCH_SIZE).forEach((file) => {
body.append("file", file); // use "file[]" for the first arg if required
});
try {
const res = await fetch(UPLOAD_URL, { method: "POST", body });
if (!res.ok) {
throw new Error(`${res.status} ${res.statusText}`);
}
console.log(`Batch ${i + 1} passed`);
} catch (err) {
console.warn(`Batch ${i + 1} failed`, err);
}
}
and this for Axios
for (let i = 0; i < files.length; i += BATCH_SIZE) {
try {
await axios.postForm(
{
file: files.slice(i, i + BATCH_SIZE),
},
{
formSerializer: {
indexes: null, // set to false if you need "[]" added
},
}
);
console.log(`Batch ${i + 1} passed`);
} catch (err) {
console.warn(`Batch ${i + 1} failed`, err.response?.data);
}
}
You can use a combination of JavaScript's for loop and Promise.all functions to achieve this. First, you will need to divide your files array into chunks of 3. You can do this using a for loop and the slice method. Next, you can use Promise.all to send all the requests in parallel, and only move on to the next set of requests once all the promises in the current set have been resolved. Here's some sample code that demonstrates this approach:
const chunkSize = 3;
for (let i = 0; i < files.length; i += chunkSize) {
const fileChunk = files.slice(i, i + chunkSize);
const promises = fileChunk.map(file => {
return axios.post('/api/upload', { file });
});
await Promise.all(promises);
}
This will send 3 post request at a time and will wait until all the request are completed before sending another 3 api request.
You can also use useState hook with useEffect to set the state of files that are uploaded and use a variable to keep track of number of files uploaded.
const [uploadedFiles, setUploadedFiles] = useState([]);
const [uploadCount, setUploadCount] = useState(0);
useEffect(() => {
if (uploadCount === files.length) {
// all files have been uploaded
return;
}
const chunkSize = 3;
const fileChunk = files.slice(uploadCount, uploadCount + chunkSize);
const promises = fileChunk.map(file => {
return axios.post('/api/upload', { file });
});
Promise.all(promises).then(responses => {
setUploadedFiles([...uploadedFiles, ...responses]);
setUploadCount(uploadCount + chunkSize);
});
}, [uploadCount]);
This code will work for you.

Can React Native store a large amount of information

I want to store 100000 record in my application so i can use it in offline mod first I try to use Asyncstorage
try{
await AsyncStorage.setItem(#Devices, JSON.stringify(data));
}
but I have problem when I try to get the saved data
let Devices = await AsyncStorage.getItem('#Devices');
let newList = await JSON.parse( Devices );
AsyncStorage throw error :
AsyncStorage Couldn't read row 0, col 0 from CursorWindow
then I try to use react-native-sqlite-storage I face problem where
I have a problem that the data must be added one by one (for loop to insert 100000 record) and this led to the application being stuck
// Didmount
useEffect(() => {
createTable();
});
const createTable = () => {
db.transaction(tx => {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS' +
'USERS' +
'(ID INTEGER PRIMARY KEY AUTOINCREMENT,item_code TEXT,item_desc TEXT,ser_id TEXT,inv_no TEXT,status TEXT,location TEXT,)',
);
});
};
const insertIntoTable = () => {
deviceList.map(item=>{
db.transaction(tx => {
tx.executeSql(
'INSERT INTO USERS (item_code,item_desc,ser_id,inv_no,status,location) VALUES (?,?,?,?,?,?,)',
[item.item_code, item.item_desc, item.ser_id, iitem.nv_no, item.status, item.location],
);
});
})
};
you have to call transaction at first ,and define loop in , it's something like this :
try {
db.transaction(
tx => {
deviceList.forEach(async item => {
await tx.executeSql(
'INSERT INTO USERS (item_code,item_desc,ser_id,inv_no,status,location) VALUES (?,?,?,?,?,?,)',
[item.item_code, item.item_desc, item.ser_id, iitem.nv_no, item.status, item.location],
);
});
},
null,
null,
);
} catch (error) {
result = false;
}
maybe it's Helpful :)
I solved my problem by dividing the data into 10,000 for each one, so the 100,000 divided into 10 AsyncStorage
let loop = (await res.items.length) / 10000;
let loop2 = (await loop) % 1 === 0 ? loop : parseInt(loop) + 1;
let first = -10000;
let second = 0;
let last = res.items.length;
await AsyncStorage.setItem('loop', loop2.toString());
for (var i = 0; i < loop2; i++) {
first = first + 10000;
second = i + 1 == loop2 ? last : second + 10000;
let data = await res.items.slice(first, second);
try {
let Device = await ('#Device' + i + 1);
await AsyncStorage.setItem(Device, JSON.stringify(data));
if (i + 1 == loop2) {
setIsLoading(false);
}

Why doesn't the parser wait for Promise.resolve?

I am using React and I do not understand why in the useEffect when running a map function the second part of the code runs before the first part (which is a promise resolve).
Shouldn't the parser wait for the promise to resolve and then run the second part of the code?
useEffect(() => {
const pools = mainnet.Exchanges.Pancakeswap.LpTokens.map((lpPool) => {
// part 1
const [tokenZeroSymbol, tokenOneSymbol] = lpPool.name.replace(' LP', '').split('-');
const prices = fetchTokenPrice(tokenZeroSymbol.toLowerCase(), tokenOneSymbol.toLowerCase());
Promise.resolve(prices).then((values) => {
const [priceTokenZero, priceTokenOne] = values;
filteredFarmPools.find((pool) => {
if (lpPool.name.replace(' LP', '') === pool.name) {
pool.priceTokenZero = values[0].usd;
pool.priceTokenOne = values[1].usd;
}
console.log('inside the fethcprice promise');
});
});
// part 2
filteredFarmPools.find((pool) => {
if (lpPool.name.replace(' LP', '') === pool.name) {
const tvl0 = (pool.reserveTokenZero / 10 ** 18) * pool.priceTokenZero;
const tvl1 = (pool.reserveTokenOne / 10 ** 18) * pool.priceTokenOne;
pool.tvl = tvl0 + tvl1;
}
console.log('inside the tvl calc');
});
});
No.
Promises give you an object that you can pass around and call then on.
They do not turn asynchronous code into blocking code.
The second part of the code isn't inside the then callback so it runs while the asynchronous code (that will trigger the first promise to resolve) is running in the background.
That said, see the await keyword for asyntax that can give the illusion that a promise is blocking.
useEffect(() => {
const processPools = async () => {
for (let lpPool of mainnet.Exchanges.Pancakeswap.LpTokens) {
const [tokenZeroSymbol, tokenOneSymbol] = lpPool.name.replace(' LP', '').split('-');
const values = await fetchTokenPrice(tokenZeroSymbol.toLowerCase(), tokenOneSymbol.toLowerCase());
// Promise.resolve(prices).then((values) => {
const [priceTokenZero, priceTokenOne] = values;
filteredFarmPools.find((pool) => {
if (lpPool.name.replace(' LP', '') === pool.name) {
pool.priceTokenZero = values[0].usd;
pool.priceTokenOne = values[1].usd;
}
console.log('inside the fethcprice promise');
// });
});
}
}
processPools();
});
Original Array.map does not support async
Promise.resolve return immediately, no difference with Promise.then

Discord Votemute Bot

it is invalid and I dont know how to fix it (it is for a Discord Votemute Bot).
if(!msg.mentions.users.first()) return msg.channel.send('You need to mention somebody!'); // Check if no User was Mentioned
const voting = new Discord.RichEmbed() // Generate Voting Embed
.setColor('#42b34d')
.setFooter('Mute ' + msg.mentions.users.first().tag + ' for 10m?')
.setImage(msg.mentions.users.first().avatarURL);
const role = msg.guild.roles.find(r => r.name === 'Muted'); // Find Role
if(!role) return msg.channel.send('No Role was found, please make sure you have a muteed role!'); // Make sure there is a Role
const agree = '✅'; // Define Emojis
const disagree = '❌'; // Define Emojis
const sentEmbed = await msg.channel.send(voting); // Send Embed
const filter = (reaction, user) => (reaction.emoji.name === agree || reaction.emoji.name === disagree) && !user.bot; // Filter for Reactions
await sentEmbed.react(agree); // React
await sentEmbed.react(disagree); // React
const voteStatus = await msg.channel.send('Voting started 30 seconds left'); // Send start Message and
const collected = await sentEmbed.awaitReactions(filter, { time: 5000 }); // start Collecting Reactions
const agreed = collected.get(agree) || { count: 1 }; // Retrieve Reactions
const disagreed = collected.get(disagree) || { count : 1 }; // Retrieve Reactions
const agreed_count = agreed.count - 1 ; // Count away Bot Votes
const disagreed_count = disagreed.count - 1; // Count away Bot Votes
voteStatus.edit('Voting endet with: ' + agreed_count + agree + ' and ' + disagreed_count + disagree); // Edit message to show Outcome
if(agreed.count > disagreed.count) {
await msg.guild.member(msg.mentions.users.first()).addRole(role);
await wait(600000);
await msg.guild.member(msg.mentions.users.first()).removeRole(role);
}
else {
msg.channel.send('Mute Voting Failed :)');
}
For reasons I could not pinpoint, msg.guild.member(msg.mentions.users.first()) returns null. The way I managed to get the guild member from the mention is with:
msg.guild.fetchMember(msg.mentions.users.first())
.then(async member => {
...
});
Furthermore, there is no wait function I'm aware of in js, so I replaced that as well, leaving your code looking like this:
msg.guild.fetchMember(msg.mentions.users.first())
.then(async member => {
await member.addRole(role);
setTimeout(function () { member.removeRole(role); }, 600000);
});

Firebase upload multiple files and get status

I have a React form where the user can upload multiple files. These are stored in fileList
async function uploadFiles(id) {
try {
const meta = await storageUploadFile(fileList, id);
console.log(meta);
} catch (e) {
console.log(e);
}
}
This calls my helper function that uploads the files to Firebase
export const storageUploadFile = function(files, id) {
const user = firebase.auth().currentUser.uid;
return Promise.all(
files.map((file) => {
return storage.child(`designs/${user}/${id}/${file.name}`).put(file)
})
)
};
What I'd like is on calling uploadFiles, get the total filesize of all items, and then show the overall progress.
At the moment, my code is only returning the file status in an array on completion
[
{bytesTransferred: 485561, totalBytes: 485561, state: "success"},
{bytesTransferred: 656289, totalBytes: 656289, state: "success"}
]
This is the way i do it:
import Deferred from 'es6-deferred';
export const storageUploadFile = function(files, id) {
const user = firebase.auth().currentUser.uid;
// To track the remaining files
let itemsCount = files.length;
// To store our files refs
const thumbRef = [];
// Our main tasks
const tumbUploadTask = [];
// This will store our primses
const thumbCompleter = [];
for (let i = 0; i < files.length; i += 1) {
thumbRef[i] = storage.ref(`designs/${user}/${id}/${file.name}`);
tumbUploadTask[i] = thumbRef[i].put(files[i]);
thumbCompleter[i] = new Deferred();
tumbUploadTask[i].on('state_changed',
(snap) => {
// Here you can check the progress
console.log(i, (snap.bytesTransferred / snap.totalBytes) * 100);
},
(error) => {
thumbCompleter[i].reject(error);
}, () => {
const url = tumbUploadTask[i].snapshot.metadata.downloadURLs[0];
itemsCount -= 1;
console.log(`Items left: ${itemsCount}`)
thumbCompleter[i].resolve(url);
});
}
return Promise.all(thumbCompleter).then((urls) => {
// Here we can see our files urls
console.log(urls);
});
};
Hope it helps.

Resources