i m new to node and search a lot find solution but don't know how to use with my condition if anyone pro who can help me with this thing
Permissiontb.assembleAndInsert = async (ctx, cb) => {
for (let i = 0; i < ctx.req.body.view.length; i++) {
console.log('outside i '+i)
await Process(ctx,i);
}
};
function Process(ctx,i) {
let data={company_id:ctx.args.options.accessToken.userId,
userid:ctx.req.body.userid,
perpage:ctx.req.body.perpage[i].id,
view:ctx.req.body.view[i],
edit:ctx.req.body.edit[i],
update:ctx.req.body.update[i],
delete:ctx.req.body.delete[i]}
console.log('inside '+i)
return new Promise((resolve, reject) => {
Permissiontb.find({where:{and: [{userid:ctx.req.body.userid}, {perpage:ctx.req.body.perpage[i].id}] }},function(err,result){
if(err){
var err = new Error('Some thing went wrong');
err.statusCode = 444;
console.log('err'+err)
resolve(err)
}else{ console.log(result.length)
if(result.length>0){
console.log(ctx.req.body.userid)
console.log('page id '+ctx.req.body.perpage[i].id)
const pgid=ctx.req.body.perpage[i].id
const vd=ctx.req.body.view[i]
const ed=ctx.req.body.edit[i]
const up=ctx.req.body.update[i]
const del=ctx.req.body.delete[i]
console.log(ctx.req.body.view[i])
console.log(ctx.req.body.edit[i])
console.log(ctx.req.body.update[i])
console.log(ctx.req.body.delete[i])
console.log('findinside update '+i)
resolve(Permissiontb.update({where:{and: [{userid:ctx.req.body.userid}, {perpage:pgid}] }},{view:vd,edit:ed,update:up,delete:del}))
}else{
resolve(Permissiontb.create([data]))
}
}
})
})
}
now problem is that console log inside if(result.lenght>0) condition for eg:- console.log(ctx.req.body.view[i]) correct value getting but when update method always inserting last array value can anyone tell me what i m doing wrong
finally i found soultion may be this will help other who facing issue like me
var async = require('async');
module.exports = function(Permissiontb) {
Permissiontb.assembleAndInsert = async (ctx, cb) => {
for (let i = 0; i < ctx.req.body.view.length; i++) {
await Process(ctx,i);
}
};
Permissiontb.remoteMethod('assembleAndInsert', {
http: {
path: '/assembleAndInsert',
verb: 'post',
},
accepts: [{ arg: 'data', type: 'object', http: { source: 'context' } },
{"arg": "options", "type": "object", "http": "optionsFromRequest"}],
returns: {
arg: 'data',
type: 'object',
},
});
function Process(ctx,i) {
let data={company_id:ctx.args.options.accessToken.userId,
userid:ctx.req.body.userid,
perpage:ctx.req.body.perpage[i].id,
view:ctx.req.body.view[i],
edit:ctx.req.body.edit[i],
update:ctx.req.body.update[i],
delete:ctx.req.body.delete[i]}
return new Promise((resolve, reject) => {
resolve(Permissiontb.upsertWithWhere({userid:ctx.req.body.userid,perpage:ctx.req.body.perpage[i].id},data))
})
}
problem is that i m using Permissiontb.upsertWithWhere(//im using where here->{userid:ctx.req.body.userid,perpage:ctx.req.body.perpage[i].id},data))
Related
The Following code works on ioredis scanstream. I am trying to do it on node-redis in typescript.
It scans a stream and returns gameIds to an Express client, when it reaches 'end' it returns the results to the client.
const stream = redis.scanStream({
match: "kaboom:moves:*",
});
const gameIds: any = [];
This is my attempt:
const stream = client.scanIterator({
TYPE: "string", // `SCAN` only
MATCH: "kaboom:moves:*",
COUNT: 100,
});
const LIMIT = 3;
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
next() {
const done = i === LIMIT;
const value = done ? undefined : i++;
return Promise.resolve({ value, done });
},
return() {
// This will be reached if the consumer called 'break' or 'return' early in the loop.
return { done: true };
},
};
},
};
(async () => {
for await (const keys of stream) {
gameIds.push(keys.split(":")[2]);
}
})();
const gameIds: any = [];
How do I write this part so that it will work with node-redis in typescript?
stream.on('data', (keys: any) => {
//Extract the gameId from the key and append to gameIds array.
keys.forEach((key: any) => gameIds.push(key.split(':')[2]));
});
stream.on('end', () => {
res.status(200).json({
data: {
gameIds,
length: gameIds.length
},
status: 'success',
})
})
ScanIterator was correct.
const stream = client.scanIterator({
TYPE: 'string', // `SCAN` only
MATCH: 'kaboom:moves:*',
COUNT: 100
});
const LIMIT = 3;
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
next() {
const done = i === LIMIT;
const value = done ? undefined : i++;
return Promise.resolve({ value, done });
},
return() {
// This will be reached if the consumer called 'break' or 'return' early in the loop.
return { done: true };
}
};
}
};
(async () => {
for await (const keys of stream) {
gameIds.push(keys.split(':')[2]);
}
})();
I'd like to check if uploading files are used in my database. So I'd like to list all files in the "uploads" folder and then check with SequelizeJs if item are finded with the right property.
My code seems not working as espected :
var promises = [];
fs.readdir('./public/uploads', (err, files) => {
if (!err) {
promises = files.filter(function(file) {
if (file !== 'csv' && file !== '.gitignore') {
// vérification dans FileModel
return models.FileModel.findOne({ where: { name: '/uploads/' + file } }).then(function(findedFile) {
if (!findedFile) {
return Promise.resolve(file).then(function() {
// Vérification dans VehiclePhotoModel
return models.VehiclePhotoModel.findOne({ where: { name: '/uploads/' + file } }).then(function(findedFile) {
if (!findedFile) {
return Promise.resolve(file);
}
});
});
}
});
}
});
}
});
Promise.all(promises).then(function(unusedFiles) {
response.render('file/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles
});
});
Edit #1 :
I've mixed up your code that doesn't work for me but I still get an issue, the Promise.resolve() is not returning the string name file.
const fileModels = [
{ model: models.FileModel, property: 'name' },
{ model: models.VehiclePhotoModel, property: 'name' }
];
function _checkUnusedFiles(request, response) {
var promises = [],
files = _.remove(fs.readdirSync('./public/uploads'), function(file) {
return file !== 'csv' && file !== '.gitignore';
});
promises = _.map(files, function(file) {
return fileModels.map(function(fileModel) {
var where = {};
where[fileModel.property] = file;
return fileModel.model.findOne({ where: where }).then(function(findedItem) {
if (!findedItem) {
return Promise.resolve(file);
}
});
});
});
Promise.all(promises).then(function(unusedFiles) {
response.render('optimizer/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles
});
});
}
With the above code soon you get into callback hell, which will result in issues like the ones you have mentioned. Anyways, so the problem is as follows
files.filter returns
<string[]> | <Buffer[]> | <fs.Dirent[]>
taken from documentation:https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback
a better approach would be to loop and then do something like promises.append(...)
even better approach break down your code using async await to avoid callback hell and issues like this
You really don't need Promise.all in your case as it might complicated things even further and could be a performance bottleneck.
Something like this should work fine
const fs = require('fs')
const path = require('path')
// Mocking SequeliseJS (You can remove this and replace in code as well with original models
const modelsMock = {
FileModel: {
findOne: (query) => {
return new Promise((resolve, reject) => {
// rand will just randomize result between true and false
let rand = Math.floor(Math.random() * Math.floor(2))
resolve(rand == 1 ? resolve(true) : resolve(false))
})
}
},
VehiclePhotoModel: {
findOne: (query) => {
return new Promise((resolve, reject) => {
// rand will just randomize result between true and false
let rand = Math.floor(Math.random() * Math.floor(2))
resolve(rand == 1 ? resolve(true) : resolve(false))
})
}
}
}
run()
async function run() {
let promises = []
let existFiles = []
let doesntExistFiles = []
// If the goal is to use readdir async then uncomment the following and comment let files = fs.readdirSync('./public/uploads')
/*
const util = require('util')
const readdir = util.promisify(fs.readdir);
let files = await readdir('./public/uploads')
*/
let files = fs.readdirSync('./public/uploads')
// Filter files: (using array.filter is pretty useless to us here since we can't run it async unless we want to promisify it which there are plenty of examples out there, for now we will stick with good old fashion loop)
for(var i = 0; i < files.length; i++) {
const file = files[i]
if(path.extname(file) !== '.csv' && path.extname(file) !== '.gitignore') {
try {
let exist = await checkIfFileExist(file, modelsMock)
exist === true ? existFiles.push(file) : doesntExistFiles.push(file)
} catch (e) {
// Handle error here
}
}
}
response.render('file/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles //Note this will break the code as unusedFiles is undefined, I really dont know what is this variable hence I didn't change it but feel free to change it as you see it appropriate.
});
}
async function checkIfFileExist(file, models){
let query = `{ where: { name: '/uploads/' + ${file} } }`
try {
let existInFiles = await models.FileModel.findOne(query)
if(!existInFiles) {
let existInVehicle = await models.VehiclePhotoModel.findOne(query)
existInVehicle ? return true : return false
} else {
return true
}
}
catch(e) {
throw e
}
}
here is the full example working on Repl.it
https://repl.it/repls/DramaticAwfulSpreadsheets#index.js
EDIT1:
Like I mentioned in the comments I don't really suggest what you are doing (My opinion at least :)); however, if you flatten your array everything should be fine.
const fileModels = [
{ model: models.FileModel, property: 'name' },
{ model: models.VehiclePhotoModel, property: 'name' }
];
function _checkUnusedFiles(request, response) {
var promises = [],
files = _.remove(fs.readdirSync('./public/uploads'), function(file) {
// I think you want to check for extension here and not the file name? if so use this
// return (path.extname(file) !== '.csv' && path.extname(file) !== '.gitignore') //Make sure to require('path')
return file !== 'csv' && file !== '.gitignore';
});
promises = _.map(files, function(file) {
return fileModels.map(function(fileModel) {
var where = {};
// Your query seems wrong? at least different from last time. If it is intentional then you are good otherwise I think you meant to do
// where[fileModel.property] = `/uploads/${file}`
where[fileModel.property] = file;
return fileModel.model.findOne({ where: where }).then(function(findedItem) {
if (!findedItem) {
return Promise.resolve(file);
}
});
});
});
// Your promises array is more like a 2d array because each file will map to an array of 2 promises
// So if you flatten it, you should get a 1D promises array
promises = promises.flat()
Promise.all(promises).then(function(unusedFiles) {
response.render('optimizer/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles
});
});
}
If you don't flatten the output of promises looks something like the following
promises =
[
[ Promise { <pending> }, Promise { <pending> } ],
[ Promise { <pending> }, Promise { <pending> } ]
]
Each entry is a file which has 2 promises for each model
So when you do Promise.all(promises) it really doesn't know how interpret that in 2D arrays; However, when you flatten it, your output looks something similar to:
promises =
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
Now keep in mind unusedFiles output may look weird and that is because not every promise will actually resolve to something meaningful, at least that is what you are mapping.
For some reason, exec() is not awaiting in my code:
let team = <SOME TEAM NAME> //putting manually for testing
let results = []
TeamModel.find({ name: team })
.exec(async (err, docs) => {
if (err)
return res.send(Response("failure", "Error occured while retrieving fixtures"))
for(let i = 0; i < docs.length; i++){
let doesExist = await FixtureModel.exists({ leagueName: docs[i].leagueName })
if (doesExist) {
let query = FixtureModel.find({ leagueName: docs[i].leagueName, $or: [{ homeTeam: team }, { awayTeam: team }] })
await query.exec((err2, docs2) => {
if (err2)
return res.send(Response("failure", "Error occured while retrieving fixtures"))
docs2.forEach((doc2, index) => {results.push(doc2.toObject())})
console.log('during await') //Executes second
})
console.log('after await') //Executes first
}
else { //This section is not required
let result = await Communicator.GetFixturesFromLeague(docs[i].leagueId)
result.api.fixtures.forEach((fixture, index) => {
let newFixture = new FixtureModel({
fixtureId: fixture.fixture_id,
leagueId: fixture.league_id,
leagueName: fixture.league.name,
eventDate: fixture.event_date,
statusShort: fixture.statusShort,
homeTeam: fixture.homeTeam.team_name,
awayTeam: fixture.awayTeam.team_name
})
newFixture.save()
results.push(newFixture.toObject())
})
}
}
console.log(results)
res.send(Response("success", "Retrieved fixtures", results))
})
and the result looks something like this:
after await
[]
during await
and therefore an empty array of results is sent before values are added inside. I'm not sure what I'm missing here.
This is a workaround if anyones wondering. Sending the response inside the exec() callback when the forLoop completes bypassing the need for async/await.
if (doesExist) {
let query = FixtureModel.find({ league_name: docs[i].leagueName, $or: [{ homeTeam: { team_name: team} }, { awayTeam: { team_name: team} }] })
await query.exec((err2, docs2) => {
if (err2)
return res.send(Response("failure", "Error occured while retrieving fixtures"))
docs2.forEach((doc2, index) => {results.push(doc2.toObject())})
if(i + 1 == docs.length){
return res.send(Response("success", "Retrieved fixtures", results))
}
})
}
I need help with code below. I get an array of items from the client then the goal is to save them in mongodb and return the list classified as 'saved' and 'failed' items. sample of failed items are those that are duplicate on a unique attribute.
I know the code below will not work because of variable scope. how do i get around it? the code below returns an empty array for both savedItems and failedItems. Thanks!
router.post('/addItems', async (req, res, next) => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
function saveData() {
for (i = 0; i < items.length; i++) {
item = items[i];
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
});
}
return result;
}
saveData().then(result => {
res.send({
results: result
});
});
});
router.post('/addItems', async (req, res, next) => {
// use try catch when use async
try {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
for (let i = 0; i < items.length; i++) {
const item = items[i];
// use the returned promise instead of callback for Model.create
const data = await Model.create({ ...item });
result.savedItems.push(item);
// if also need to handle failed item in result use anathor try catch inside
/*try {
const data = await Model.create({ ...item });
result.savedItems.push(item);
} catch( err ) {
result.failedItems.push(item);
}*/
}
res.send({
results: result
});
} catch( err ) {
// To all the errors unexpected errors + thrown rejected promises
res.send({
error: err
});
}
});
Your saveData method didn't return a promise, try this
function saveData() {
return new Promise(resolve => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
let promises = [];
for (i = 0; i < items.length; i++) {
item = items[i];
let promise = new Promise(resolve => {
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
resolve();
});
});
promises.push(promise);
}
Promise.all(promises).then(() => resolve(result));
})
}
I have a collection called 'alldetails' which have the details of some collection
{
"name" : "Test1",
"table_name" : "collection1",
"column_name" : "column1"
},
{
"name" : "Test2",
"table_name" : "collection2",
"column_name" : "column2"
},
{
"name" : "Test3",
"table_name" : "collection3",
"column_name" : "column3"
}
I have collection1,collection2 and collection3 which have column1,column2,colum3 respectively
I have to fetch all the name from the 'alldetails' and I have to get the min and max value of other table based on the column name.
So I want the output like below
{name: ["Test1","Test2","Test3"],
date: [{min_date: "2018-12-01", max_date: "2018-12-31", name: "Test1"},
{min_date: "2018-12-01", max_date: "2018-12-31", name: "Test2"},
{min_date: "2018-12-01", max_date: "2018-12-31", name: "Test3"}]
}
I tried the below code because of non blocking its not waiting the response.
alldetails.find({}, { _id: 0 }).then(async function(result) {
let result_data = {};
let resolvedFinalArray = {};
let array = [];
result_data["name"]= [];
result_data["date"] = [];
resolvedFinalArray = await Promise.all(result.map(async value => {
result_data["name"].push(value.name)
getResult(value.table_name,value.column_name,function(response){
result_data["date"].push({min_date: response.minvalue, max_date: response.maxvalue, name:value.name})
});
}));
setTimeout(function()
{
console.log(resolvedFinalArray);
}, 3000);
});
Please suggest me a solution.
If you want to wait for getResult then you need to return Promise from result.map callback.
You are not pushing anything to resolvedFinalArray so why bother with console.log(resolvedFinalArray)
alldetails.find({}, {_id: 0}).then(async (result) => {
let result_data = {};
result_data["name"] = [];
result_data["date"] = [];
await Promise.all(result.map(value => {
// create Promise that resolves where getResult callback is fired
return new Promise((resolve) => {
getResult(value.table_name, value.column_name, (response) => {
result_data["name"].push(value.name);
result_data["date"].push({
min_date: response.minvalue,
max_date: response.maxvalue,
name: value.name
});
resolve();
});
});
}));
console.log(result_data);
});
or using for loop
alldetails.find({}, {_id: 0}).then(async (result) => {
let result_data = {};
result_data["name"] = [];
result_data["date"] = [];
for (let i = 0; i < result.length; i++) {
const value = result[i];
await new Promise((resolve) => {
getResult(value.table_name, value.column_name, (response) => {
result_data["name"].push(value.name);
result_data["date"].push({
min_date: response.minvalue,
max_date: response.maxvalue,
name: value.name
});
resolve();
});
});
}
console.log(result_data);
});
use async.eachOfLimit if you want to apply an async function on all element of an array:
var async = require("async");
var array = [{_id: "...."},{...},{...}];
async.eachOfLimit(array, 1, function(element, index, cb){
myAsyncFunctionWithMyElement(element, function(err){
return cb(err);
});
}, function(err){
// final callback
});
The array forEach method won't work with async function (unless you do deeply evil things like redefining the prototype). This question has a nice insight of the internal.
If you don't want to rely on external libraries, an easy (and my favourite) approach is something like:
for (let i = 0; i < <your array>.length; i++ ) {
await Promise.all( <your logic> );
}
Just adapt it to your need! :)
You might want to use the for await of loop. See this blog post for details.
This, IMHO, is the most modern way to do it, and it doesn't require you to load any external dependencies, since it is built-in to the language itself. It's basically very similar to the classical for of loop.
This should work, if all lexical scope are taken to consideration. Async each is also is better option it would reduce if else blocks and manage promise for you.
alldetails.find({}, { _id: 0 })
.exec((err, result) => {
if (!err) {
let resolvedFinalArray = [];
result.map((value) => {
resolvedFinalArray.push({
name: value.name,
date: []
});
getResult(value.table_name, value.column_name, (err, response) => {
if (!err) {
resolvedFinalArray[resolvedFinalArray.indexOf(value.name)]['date'].push({
min_date: response.minvalue,
max_date: response.maxvalue,
name:value.name
});
} else {
// Send your error messsage.
// res.status(500).send(err);
}
});
});
console.log(resolvedFinalArray);
// res.send(resolvedFinalArray);
} else {
// Send your error messsage.
// res.status(500).send(err);
}
});