具有pg-promise的相互依赖的事务

Sel*_*çuk 3 node.js express pg-promise

我正在尝试构建一个应用程序涉及帖子帖子的标签.对于这些我有一个post,tagspost_tag表.tags有我之前定义的标签,并在应用程序的某个地方建议用户在前端.post_tagtable将posttag id保存为每行的对.

我使用express.js和postgreql以及pg-promise.

据我所知,我需要一个创建后期操作的事务查询.

此外,我需要一个机制来检测一个标签是不是在tags表中,当用户创建的帖子,让我可以在飞行中插入,然后我有一个tag_id每个标签是neccessary中使用insertionpost_idtag_idpost_tag表.否则,我将有一个,foreign key error因为我需要分别post_tag表的列post_idtag_id引用poststagsid列.

这是我用于此的url函数,到目前为止我使用的不成功:

privateAPIRoutes.post('/ask', function (req, res) {
    console.log('/ask req.body: ', req.body);
    // write to posts
    var post_id = ''
    var post_url = ''
    db.query(
        `
            INSERT INTO
                posts (title, text, post_url, author_id, post_type)
            VALUES
                ($(title), $(text), $(post_url), $(author_id), $(post_type))
            RETURNING id
        `,
        {
            title: req.body.title,
            text: req.body.text,
            post_url: slug(req.body.title),
            author_id: req.user.id,
            post_type: 'question'
        } // remember req.user contains decoded jwt saved by mw above.
    )
        .then(post => {
            console.log('/ask post: ', post);
            post_id = post.id
            post_url = post.post_url


            // if tag deos not exist create it here
            var tags = req.body.tags;
            console.log('2nd block tags1', tags);
            for (var i = 0; i < tags.length; i++) {
                if (tags[i].id == undefined) {
                    console.log('req.body.tags[i].id == undefined', tags[i].id);                        
                    var q1 = db.query("insert into tags (tag) values ($(tag)) returning id", {tag: tags[i].label})
                                .then(data => {
                                    console.log('2nd block tags2', tags);
                                    tags[i].id = data[0].id 


                                    // write to the post_tag
                                    db.tx(t => {
                                        var queries = [];
                                        for (var j = 0; j < tags.length; j++) {

                                            var query = t.query(
                                                `
                                                    INSERT INTO
                                                        post_tag (post_id, tag_id)
                                                    VALUES
                                                        ($(post_id), $(tag_id))
                                                `,
                                                {
                                                    post_id: post_id,
                                                    tag_id: tags[j].id
                                                }
                                            )
                                            queries.push(query);
                                        }   
                                        return t.batch(queries)
                                    })
                                        .then(data => {
                                            res.json({post_id: post_id, post_url: post_url})
                                        })
                                        .catch(error => {
                                            console.error(error);
                                        })
                                })
                                .catch(error => {
                                    console.error(error);
                                });
                }
            }
        })
        .catch(error => {
            console.error(error);
        })
});
Run Code Online (Sandbox Code Playgroud)

vit*_*y-t 5

您遇到的主要问题 - 您无法db在任务或事务中使用根级对象.尝试在事务内部创建新连接会破坏事务逻辑.t.tx在这种情况下你需要使用.但是,在你的情况下,我根本没有看到你需要它.

更正的代码:

privateAPIRoutes.post('/ask', (req, res) => {
    console.log('/ask req.body: ', req.body);
    db.tx(t => {
        return t.one(
            `
        INSERT INTO
        posts (title, text, post_url, author_id, post_type)
        VALUES
        ($(title), $(text), $(post_url), $(author_id), $(post_type))
        RETURNING *
        `,
            {
                title: req.body.title,
                text: req.body.text,
                post_url: slug(req.body.title),
                author_id: req.user.id,
                post_type: 'question'
            } // remember req.user contains decoded jwt saved by mw above.
        )
            .then(post => {
                console.log('/ask second query: post[0]: ', post);
                console.log('/ask second query: tags: ', req.body.tags);
                console.log('/ask second query: tags[0]: ', req.body.tags[0]);

                // the key piece to the answer:
                var tagIds = req.body.tags.map(tag => {
                    return tag.id || t.one("insert into tags(tag) values($1) returning id", tag.label, a=>a.id);
                });

                return t.batch(tagIds)
                    .then(ids => {
                        var queries = ids.map(id => {
                            return t.one(
                                `
                                INSERT INTO post_tag (post_id, tag_id)
                                VALUES ($(post_id), $(tag_id))
                                RETURNING post_id, tag_id
                                `,
                                {
                                    post_id: post.id,
                                    tag_id: id
                                }
                            )
                        });
                        return t.batch(queries);
                    });
            });
    })
        .then(data => {
            // data = result from the last query;
            console.log('/api/ask', data);
            res.json(data);

        })
        .catch(error => {
            // error
        });
});
Run Code Online (Sandbox Code Playgroud)

这里的关键是简单地遍历标记id-s,对于未设置的标记,使用插入.然后通过将阵列传入其中来解决所有问题t.batch.


其他建议:

  • 您应该one在执行返回新记录列的插入时使用方法.
  • 您应该在交易中使用try/ catch仅一次.这与如何使用promises有关,而不仅仅与此库有关
  • 您可以将查询放入外部SQL文件,请参阅查询文件

要更好地理解条件插入,请参阅SELECT-> INSERT