异步从nodeJS中的sqlite数据库获取数据

Posted

技术标签:

【中文标题】异步从nodeJS中的sqlite数据库获取数据【英文标题】:async get data from sqlite database in nodeJS 【发布时间】:2020-07-14 03:51:09 【问题描述】:

这是我的警告命令的代码,它正在从 sqlite 数据库中读取。

user = message.mentions.users.first()
embed = new Discord.MessageEmbed()
    .setTitle(`warnings of $user.username`)
    .setTimestamp()
    .setFooter('shadowcraft - **Test Mode!!**');

sql = 'SELECT * from moderation WHERE userID = ?'
db.each(sql, [user.id], (err, row) => 
    if (err) throw err;
    mod = client.user.fetch(toString(row.moderatorID))
    console.log(row)
    embed.addField(`$mod.tag`, `$row.reason \n$row.date`);
);
message.channel.send(embed)

当我运行它时,它会将行打印到控制台,但嵌入是空的并且没有字段。问题是它在从db.each() 获得结果之前发送嵌入

db.each 是回调而不是承诺,所以我不能使用 await .then()

有没有办法将回调变成一个承诺,以便我可以使用异步函数

这是完整的控制台日志,没有错误等,只有行


  id: 1,
  date: '2020-04-02',
  userID: 'some user id',
  action: 'WARN',
  reason: 'some reason',
  moderatorID: 'some user id'


  id: 2,
  date: '2020-04-02',
  userID: 'some user id',
  action: 'WARN',
  reason: 'some reason',
  moderatorID: 'some user id'

【问题讨论】:

你为什么不用WHERE userID = $message.author.id?它更容易,而且“发件人”必须大写,所以它应该是SELECT * FROM moderation WHERE userID = ? - 你不必使用?由于用户无法远程更改表中的值,因此您不容易受到 sql 注入的影响 @Proto 这是因为我不想要消息作者,我想要他们提到的用户 啊,尽管如此,请务必大写,道歉 你使用的是什么版本的 Discord.js? 我使用的是 12.1.1 【参考方案1】:

我认为如果你这样做会更干净一些。

将 db.each 更改为 db.all,回调中的行现在将是行

user = message.mentions.users.first()
embed = new Discord.MessageEmbed()
    .setTitle(`warnings of $user.username`)
    .setTimestamp()
    .setFooter('shadowcraft - **Test Mode!!**');

sql = 'SELECT * from moderation WHERE userID = ?'

db.all(sql, [user.id], (err, rows) => 
    if (err) throw err;
    Promise.all(rows.map((row) => 
        return processRow(row)
    )).then(result => 
        embed.addFields(result);
        message.channel.send(embed)
    );
);

它还允许您在行集合上完成所有承诺。然后,您将创建一个异步函数并调用该函数以返回一个承诺。这是那个功能。

var processRow = async function(row) 
    return new Promise((resolve, reject) => 
        let mod = client.user.fetch(toString(row.moderatorID))
        console.log(row);
        resolve(name: mod.tag, value: `$row.reason \n $row.date`);
    )

在所有的promise都解决后,它会使用embed.addFields方法,该方法接受一个javascript对象数组,并批量添加字段。在所有处理完成后终于能够发送嵌入。

希望对你有帮助,

【讨论】:

【参考方案2】:

看看这个,创建一个新的 Promise 并决定何时解决或拒绝,如果你愿意,你可以默默地拒绝拒绝。

const updateField = db =>
    new Promise((resolve, reject) => 
        db.each(
            'SELECT * from moderation WHERE userID = ?',
            (err, row) => 
                if (err) 
                    reject(err)
                 else 
                    mod = client.user.fetch(toString(row.moderatorID))
                    embed.addField(`$mod.tag`, `$row.reason \n$row.date`)
                
            ,
            (err, _) => 
                if (err) 
                    reject(err)
                 else 
                    resolve()
                
            
        )
    )

module.exports.main = async () => 
    //no idea what your imports/other code looks like...

    user = message.mentions.users.first()
    embed = new Discord.MessageEmbed()
        .setTitle(`warnings of $user.username`)
        .setTimestamp()
        .setFooter('shadowcraft - **Test Mode!!**')

    await updateField(db)

    message.channel.send(embed)

【讨论】:

【参考方案3】:

Tomi Kordos 几乎得到了正确答案。问题是异步执行。但是,在这种情况下,sqllite 使用回调而不是 promise,因此直接在 db.each 上使用时,await 和 .then 将不起作用。

但是有办法。 Node 提供了一个“promisify”实用程序。这适用于任何最后一个参数是错误优先回调的函数,这正是 db.each 的含义。

您首先需要引入实用程序。

const promisify = require('util');

然后创建对该函数的承诺引用。

const dbeachpr = promisify(db.each);

现在你可以像使用一个 promise 返回函数一样使用这个引用。在这种情况下,我建议将它们存储在一个数组中并使用Promise.all 来确定它们何时完成。

user = message.mentions.users.first()
embed = new Discord.MessageEmbed()
    .setTitle(`warnings of $user.username`)
    .setTimestamp()
    .setFooter('shadowcraft - **Test Mode!!**');

sql = 'SELECT * from moderation WHERE userID = ?'
let promises = [];
promises.push(dbeachpr(sql, [user.id]).then(row => 
        mod = client.user.fetch(toString(row.moderatorID))
        console.log(row)
        embed.addField(`$mod.tag`, `$row.reason \n$row.date`);
    ).catch(err => throw err); // You may want do something more useful with this.
);

Promise.all(promises).then(() => message.channel.send(embed));

【讨论】:

我收到了错误TypeError: promises.push(...).catch is not a function @Nodejs-nerd 你之前定义过承诺吗?【参考方案4】:

由于您想获取提到的用户 ID,您可以在 SQL 命令中使用 user.id, 因此,在您的情况下,您需要使用以下 SQL 查询:

`SELECT * from moderation WHERE userID = $user.id`

这样您就可以查询某人的用户 ID 并从中找到所需的警告信息。如果您需要更多解释,请告诉我:)

【讨论】:

【参考方案5】:

我不确定,因为我没有使用过 sqlite,但我认为,您正在尝试在实际添加字段之前发送嵌入。 (您正在同步运行该函数)

https://www.npmjs.com/package/sqlite#each

使您的函数异步并使用await db.each,因此它将等到循环结束,添加所有字段,然后发送嵌入。

或者你可以使用.then()

【讨论】:

我已经尝试过这样做,结果和以前一样,我从 eslint 得到一个错误,说它没有效果

以上是关于异步从nodeJS中的sqlite数据库获取数据的主要内容,如果未能解决你的问题,请参考以下文章

从 Nodejs 中的 mySQL 获取数据时如何从 Async/await 函数获取返回值

如何在不返回 Promise 的情况下从对象的`get()` 获取异步数据

NodeJs中的异步

无法从片段中的 SQLite 获取数据

在nodejs sequelize中循环获取异步数据

如何从 Javascript 中的 SQLite 数据库中获取表数据?