【问题标题】:Pushing query results into an object将查询结果推送到对象中
【发布时间】:2019-02-14 00:47:45
【问题描述】:

我正在开展一个私人项目,以创建我参加过的音乐会列表。

我有这些表:

  • vi_concert(id、标题、日期、地点)
  • vi_artist(id、name、perma)
  • vi_location (id, name, perma)
  • vi_artist_concert (artist_id, Concert_id)

我做了 2 个查询。一张是演唱会信息,一张是阵容信息:

router.get('/:id', (req, res) => {
    var output = [];

    // Get Concert Information
    let concert = `SELECT c.date, c.title, l.name AS location 
    FROM vi_concert c
    INNER JOIN vi_location l ON c.location=l.id
    WHERE c.id = '${req.params.id}'`;

    db.query( concert, (err, result) => {
        if ( err ) throw err;
        output.push(result);
    });

    let lineup = `SELECT a.name, a.perma 
    FROM vi_artist_concert ac 
    JOIN vi_artist a ON a.id = ac.artist_id 
    JOIN vi_concert c ON c.id = ac.concert_id 
    WHERE ac.concert_id = '${req.params.id}'`;

    db.query( lineup, (err, result) => {
        if ( err ) throw err;
        output.push(result);
    });

    res.send(JSON.stringify(output));
});

当我调用 URL localhost:3000/concerts/1 时,我得到以下信息:

[ ]

但我想要这样的东西:

[
    "concert": {
        "date": "2019-02-16 19:30:00",
        "title": "Fancy title",
        "location": "Fancy location"
    },
    "lineup": [
        {
            "name": "Band 1",
            "perma": "band-1"
        },
        {
            "name": "Band 234",
            "perma": "band-234"
        }
    ]
]

【问题讨论】:

  • 虽然我不记得 node.js mysql 客户端,但我敢打赌它是异步的,您需要将 res.send() 调用嵌套在 db.query 回调中。使用 Promise 包装器可能会更容易。

标签: javascript mysql node.js


【解决方案1】:

Javascript 是异步的。这意味着您的代码无需等待数据库查询结束就发送JSON.stringify(output)

您必须:

  • 执行第一个查询,然后执行第二个查询,然后发送输出 或
  • 并行执行第一个和第二个查询,然后发送输出

第一种方式,无需任何额外的库:

router.get('/:id', (req, res) => {
    var output = [];

    // Get Concert Information
    let concert = `SELECT c.date, c.title, l.name AS location 
    FROM vi_concert c
    INNER JOIN vi_location l ON c.location=l.id
    WHERE c.id = '${req.params.id}'`;

    let lineup = `SELECT a.name, a.perma 
    FROM vi_artist_concert ac 
    JOIN vi_artist a ON a.id = ac.artist_id 
    JOIN vi_concert c ON c.id = ac.concert_id 
    WHERE ac.concert_id = '${req.params.id}'`;

    db.query( concert, (err, result) => {
        if ( err ) throw err;
        output.push(result);
        db.query( lineup, (err2, result2) => {
            if ( err2 ) throw err2;
            output.push(result2);

            res.send(JSON.stringify(output));
        });        
    }); 
});

async 库的第二种方式:

var async = require('async');

router.get('/:id', (req, res) => {
    var output = [];

    // Get Concert Information
    let concert = `SELECT c.date, c.title, l.name AS location 
    FROM vi_concert c
    INNER JOIN vi_location l ON c.location=l.id
    WHERE c.id = '${req.params.id}'`;

    let lineup = `SELECT a.name, a.perma 
    FROM vi_artist_concert ac 
    JOIN vi_artist a ON a.id = ac.artist_id 
    JOIN vi_concert c ON c.id = ac.concert_id 
    WHERE ac.concert_id = '${req.params.id}'`;

    async.parallel([
        function(callback){
            db.query( concert, (err, result) => {
                if ( err ) return callback(err);
                output.push(result);
            });
        }, function(callback){
            db.query( lineup, (err, result) => {
                if ( err ) return callback(err);
                output.push(result);
            });   
        }
    ], function(err){
        if(err)
            throw err;
        res.send(JSON.stringify(output));
    })
});

如果您的数据库驱动程序支持,您也可以使用 promises,但我会让您在自己的时间使用 Google 搜索。

【讨论】:

  • 这对我有帮助,谢谢!但是我怎样才能实现,我必须像我的示例中那样为音乐会对象“音乐会”和“阵容”对象?
【解决方案2】:

在发送响应之前,您无需等待数据库中的记录。
db.query() 方法是一个异步操作,在调用回调之前不可用。

您可以在代码中更改以使其正常工作的是将查询嵌套在另一个回调中,并仅在获得数据库结果后发送响应。

router.get('/:id', (req, res) => {
    var output = [];

    // Get Concert Information
    let concert = `SELECT c.date, c.title, l.name AS location 
    FROM vi_concert c
    INNER JOIN vi_location l ON c.location=l.id
    WHERE c.id = '${req.params.id}'`;

    db.query( concert, (err, result) => {
        if ( err ) throw err;
        output.push(result);

        // Nesting the second query in the first query callback

        let lineup = `SELECT a.name, a.perma 
        FROM vi_artist_concert ac 
        JOIN vi_artist a ON a.id = ac.artist_id 
        JOIN vi_concert c ON c.id = ac.concert_id 
        WHERE ac.concert_id = '${req.params.id}'`;

        db.query( lineup, (err, result) => {
            if ( err ) throw err;
            output.push(result);

            // Sending the response to browser only after getting the second result
            res.send(JSON.stringify(output));
        });
    });
});

另一种方法是使用Promises。
较新版本的 Node.js 支持 async/await 语法。

【讨论】:

    猜你喜欢
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    • 2018-09-17
    • 2014-02-11
    • 1970-01-01
    相关资源
    最近更新 更多