简体   繁体   中英

sequential queries from database using sequalize in node+express

I am just starting node and am from PHP background. I have been trying to figure out promisses for some time now but unable to figure it out.

I am trying to use result of one query in 2nd query in a loop, but having TWO issues:

-ONE: typeof value shows an object; but when I console it out, it shows undefined

-TWO: my results are not getting in the right order. I am trying to use 'then()' but not able to quite figure it out. "inside promise 2" is consoled out before the loop in 'then()' 1 block

Here's what I'm doing in code:

exports.followers_temp = function(req, res)
{
    db.sequelize.query('SELECT DISTINCT public."Users".id as user_id, public."Users".full_name, public."Users".profile_image_url, (SELECT COUNT(*) FROM public."Followships" WHERE public."Followships".leader_id = public."Users".id AND public."Followships".follower_id = :leader_id) AS is_followed FROM public."Users"  INNER JOIN public."Followships" ON public."Users".id = public."Followships".follower_id WHERE  public."Followships".leader_id = :leader_id LIMIT :limit OFFSET :offset',  { replacements: { leader_id: req.params.leader_id, limit: req.params.limit, offset: req.params.offset }, type: db.sequelize.QueryTypes.SELECT}).
    then(function(data){
      console.log('i am here; length: ' + data.length);
        return new Promise(function(resolve, reject) {
              console.log('inside promise 1, should have access to data object');

              console.log('before loop');
              for(let i=0; i < data.length; i++){
                  var temp = db.sequelize.query('(SELECT COUNT(*) AS is_following FROM public."Followships" WHERE public."Followships".leader_id = ' + data[i].user_id + ' AND public."Followships".follower_id = :my_id)',  { replacements: { leader_id: req.params.leader_id, my_id: req.params.my_id, limit: req.params.limit, offset: req.params.offset }, type: db.sequelize.QueryTypes.SELECT})
                  temp.then(function(value){

                    // Issue ONE
                      console.log('type: '+ typeof value); // it's an object
                      console.log('is_following: '+ value.is_following); // yet it's giving undefined

                      console.log('value: '+ JSON.stringify(value)); // but it prints out when I stringify it

                      data[i].is_followed = value.is_following;
                  });
              }
            resolve(data);
            });
    })

    .then(function(my_array){
        // Issue TWO
        console.log('inside promise 2');

        return res.status(200).send({
            error:false,
            message: my_array
        });
    })
        .catch(function(err) {
            console.log('inside promise catch');
            return res.status(400).send({
                error:true,
                message: errorHandler.getErrorMessage(err)
            });
        });
};

and here is the console output:

i am here; length: 5          
inside promise 1, should have 
before loop                   
inside promise 2              
type: object                  
is_following: undefined       
value: [{"is_following":"1"}] 
type: object                  
is_following: undefined       
value: [{"is_following":"0"}] 
type: object                  
is_following: undefined       
value: [{"is_following":"1"}] 
type: object                  
is_following: undefined       
value: [{"is_following":"1"}] 
type: object                  
is_following: undefined       
value: [{"is_following":"0"}] 

Please let me know -what am I doing wrong? -if you could working of promises syntax wise... would be great

Thanking you in anticipation; Please ignore rookie mistakes as I am a rookie as of now.

db.sequelize.query is an asynchronous call put in a for loop. This will start queries but have not successfully completed yet. So, your data is not complete yet and you are resolving it already. With Promise.all you can write it as follows:

Promise.all(data.map((val) => { // here val = data[i] inside the query
    return new Promise((resolve, reject) => {
        db.sequelize.query(...)
            .then((value) => {
                // modify your data object here.
                resolve();
            });
    });
})).then(() => { resolve(data);});

You do not need to use new Promise if you already have a promise:

exports.followers_temp = function (req, res) {
  db.sequelize.query('SELECT DISTINCT public."Users".id as user_id, public."Users".full_name, public."Users".profile_image_url, (SELECT COUNT(*) FROM public."Followships" WHERE public."Followships".leader_id = public."Users".id AND public."Followships".follower_id = :leader_id) AS is_followed FROM public."Users"  INNER JOIN public."Followships" ON public."Users".id = public."Followships".follower_id WHERE  public."Followships".leader_id = :leader_id LIMIT :limit OFFSET :offset', { replacements: { leader_id: req.params.leader_id, limit: req.params.limit, offset: req.params.offset }, type: db.sequelize.QueryTypes.SELECT })
  .then(function (users) {
    console.log('i am here; length: ' + users.length);
    //do not use new Promise if you already have a promie
    //https://stackoverflow.com/a/48576246/1641941
    //use promise.all and map data to promises
    return Promise.all(
      users.map(
        user=>{
          db.sequelize.query(
            '(SELECT COUNT(*) AS is_following FROM public."Followships" WHERE public."Followships".leader_id = :leader_id AND public."Followships".follower_id = :my_id)', 
            { replacements: 
              { leader_id: user.user_id,//changed leader_id
                my_id: req.params.my_id//removed limit and offset 
              },
              type: db.sequelize.QueryTypes.SELECT 
            })
            .then(function (value) {
              console.log('type: ' + typeof value);
              //value is an array
              console.log('is_following: ' + value[0].is_following);
              console.log('value: ' + JSON.stringify(value));    
              user.is_followed = value[0].is_following;
              return user;
            });
        }
      )
    )
  })
  .then(function (users) {
    // Issue TWO
    console.log('inside promise 2',users);
    return res.status(200).send({
      error: false,
      message: users
    });
  })
  .catch(function (err) {
    console.log('inside promise catch',err);
    return res.status(400).send({
      error: true,
      message: errorHandler.getErrorMessage(err)
    });
  });
};

After searching stackoverflow in more depth, I was able to solve my problem. I used help provided on THIS POST .

I thank stackoverflow community for all the help. I will try to contribute as well in future.

Final solution looks like this:

    exports.followers_temp = function (req, res) {
    db.sequelize.query('SELECT DISTINCT public."Users".id as user_id, public."Users".full_name, public."Users".profile_image_url, (SELECT COUNT(*) FROM public."Followships" WHERE public."Followships".leader_id = public."Users".id AND public."Followships".follower_id = :leader_id) AS is_followed FROM public."Users"  INNER JOIN public."Followships" ON public."Users".id = public."Followships".follower_id WHERE  public."Followships".leader_id = :leader_id LIMIT :limit OFFSET :offset', { replacements: { leader_id: req.params.leader_id, limit: req.params.limit, offset: req.params.offset }, type: db.sequelize.QueryTypes.SELECT })
        .then(function (users) {
            var promises = users.map(function(user){
                return db.sequelize.query(
                    '(SELECT COUNT(*) AS is_following FROM public."Followships" WHERE public."Followships".leader_id = ' +
                    user.user_id + ' AND public."Followships".follower_id = :my_id)',
                    { replacements:
                            { leader_id: req.params.leader_id,
                                my_id: req.params.my_id,
                                limit: req.params.limit,
                                offset: req.params.offset
                            },
                        type: db.sequelize.QueryTypes.SELECT
                    })
                    .then(function(results){
                        user.is_followed = results[0].is_following;
                        return user
                    })
            })
            Promise.all(promises).then(function(results) {
                return res.status(200).send({
                    error: false,
                    message: users
                });
            })
                .catch(function (err) {
                    return res.status(400).send({
                        error: true,
                        message: errorHandler.getErrorMessage(err)
                    });
                });
        })
    .catch(function (err) {
        return res.status(400).send({
            error: true,
            message: errorHandler.getErrorMessage(err)
        });
    });
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM