# Writing directly to the database

**URL:** https://meta.discourse.org/t/writing-directly-to-the-database/300651
**Category:** Development
**Created:** [March 23, 2024, 1:01pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651 "2024-03-23T13:01:14Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 1:01pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/1 "2024-03-23T13:01:14Z")

</div>

Has anyone here already done work to read/write from the database directly? At first I tried to use the API to create threads and posts, but this was too unreliable, so now I’m looking at trying to write directly to the database.

The data I want to put in is quite simple: (thread title, author, category, body text) and for posts (author, body text).

However, I suspect various additional fields need to be also completed and perhaps lookups made to the user database.

I will be starting from zero so looking to see if anyone has done it before or has any pointers on the table structures or any things to watch out for.

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 1:29pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/2 "2024-03-23T13:29:13Z")

</div>

i forgot i also need to add the date/time to each (i am unable to edit my original post to update).

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [March 23, 2024, 1:37pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/3 "2024-03-23T13:37:55Z")

</div>

> [@Isambard](#):
>
> but this was too unreliable

Could you share the issues you encountered?

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 2:27pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/4 "2024-03-23T14:27:24Z")

</div>

You can see my other posts. They were regarding:

- Rate limit issues
- Validation issues
- Validation bypass not working consistently for threads vs topics

In the end, I figure it would be easier to go directly to the database.

Instead of hours of frustration trying to deal with the vagaries of the API, in a few minutes I managed to get something working and hopefully more performant:

For those wanting to do the same, notes from my exploration so far:

First enter the container:

`sudo ./launcher enter app`

Then connect to the database:

`sudo -u postgres psql discourse`

To insert a topic:  
`insert into topics (title, user_id, archetype, fancy_title, category_id, created_at, updated_at, last_post_user_id, bumped_at) values ('psql test', 1, 'regular', 'psql test',8, NOW(), NOW(), 1, NOW());`

Get the new id, in my case 886.

Then insert posts:

`insert into posts (user_id, topic_id, post_number, raw, cooked, created_at, updated_at, last_version_at) values (1,886,1,'this is the raw text','this is the cooked test',NOW(),NOW(),NOW());`

Then update `posts_count` (if not already done at topic insertion). Note it seems that the topic body needs an initial post. Below changes number of posts of the topic to be 1:

`update topics set posts_count=2 where id=886;`

---

<div class="post-metadata">

### Author: ![Firepup650](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/firepup650/32/465200_2.png) [@Firepup650](https://meta.discourse.org/u/Firepup650)
#### Post date: [March 23, 2024, 2:37pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/5 "2024-03-23T14:37:18Z")

</div>

> [@Isambard](#):
>
> i am unable to edit my original post to update

Likely because you’re on a different account?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [March 23, 2024, 2:46pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/6 "2024-03-23T14:46:18Z")

</div>

I recommend that you figure out how to use the API. Lots of magic gets handled by rails. The likelihood that you’ll do something that will make your database unusable is high.

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 7:49pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/7 "2024-03-23T19:49:26Z")

</div>

But do you see anything that can go wrong if you are just adding to topics and post tables and they are correctly formed?

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [March 23, 2024, 8:08pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/8 "2024-03-23T20:08:51Z")

</div>

This is a terrible idea.

Why do you think this is easier then either using the API or running Rails commands to create posts?

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 8:54pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/9 "2024-03-23T20:54:32Z")

</div>

> [@supermathie](#):
>
> running Rails commands

I wasn’t aware of rails commands to create posts. Do you have further details of this?

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [March 23, 2024, 9:14pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/10 "2024-03-23T21:14:28Z")

</div>

Yes, the details are: Discourse is a Rails app!

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 9:46pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/11 "2024-03-23T21:46:45Z")

</div>

> [@merefield](#):
>
> Discourse is a Rails app!

I’m aware that Discourse is a Rails app. But you said:

> [@supermathie](#):
>
> easier then either using the API or running Rails commands to create posts

So implying that there’s another way of generating threads by issuing ‘rails commands’ unless by rails command you mean manually creating accounts and typing them into discourse web front end?

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [March 23, 2024, 10:06pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/12 "2024-03-23T22:06:19Z")

</div>

It’s good practice to use the API especially if you are making a call from outside the app, because it takes care of all the authentication and authorisation as well as a lot of business logic that you can’t always assume.

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 10:13pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/13 "2024-03-23T22:13:41Z")

</div>

> [@merefield](#):
>
> authentication and authorisation

Well, one of the things I want to do is bypass all authorisation and get the post into the database without having it trip up because a user doesn’t have permission to post into a category, or the topic is too short, or there’s not enough entropy etc. etc.

It would be nice if there was a ‘superuser’ API call which bypassed all these checks and just creates the post or topic.

For example, if you want to use the API to create a topic under a user which currently has no permission to post in a certain category, you can use the bypass\_validations parameter to do this. But when you then call the API to create a reply by the same user, the validation checks are not skipped and the thread creation fails. (this is a bug which was reported 6 years ago with a pull request for a fix which never made it into the codebase).

Also, in this case, unlike with directly writing into the database, there’s no support for transactions to roll back the creation of the original thread and you have to manually find it to clean it up and fix it.

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 23, 2024, 10:52pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/14 "2024-03-23T22:52:17Z")

</div>

For now, just inserting the posts/topics seems to work OK. I was a bit worried about the ‘cooked’ column as it was not possible to have this null, but I’m just filling it in with the same text as raw for now and leaving baked\_at and baked\_version NULL.

On view, the baking process seems to be triggered quite quickly when the post is viewed.

OK. I found a way to trigger the rebake:

`rake posts:rebake`

---

<div class="post-metadata">

### Author: ![thoka](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/thoka/32/115652_2.png) [@thoka](https://meta.discourse.org/u/thoka)
#### Post date: [March 24, 2024, 6:01am UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/15 "2024-03-24T06:01:10Z")

</div>

Use specs and import scripts as a guide to manipulate discourse data structures via ruby commands.

Use the rails console for experiments.

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [March 24, 2024, 5:10pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/16 "2024-03-24T17:10:16Z")

</div>

It’s worth pointing out that if your client is written in Ruby you can use the Ruby API gem:

[https://github.com/discourse/discourse\_api](https://github.com/discourse/discourse_api)

> **[discourse\_api | RubyGems.org | your community gem host](https://rubygems.org/gems/discourse_api)**

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [March 24, 2024, 5:53pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/17 "2024-03-24T17:53:10Z")

</div>

> [@Isambard](#):
>
> OK. I found a way to trigger the rebake:

If you create the record with Rails, it’ll do the rebake automatically when the post is saved as well as send notifications and a bunch of other stuff.

---

<div class="post-metadata">

### Author: ![Isambard](https://avatars.discourse-cdn.com/v4/letter/i/858c86/32.png) [@Isambard](https://meta.discourse.org/u/Isambard)
#### Post date: [March 24, 2024, 10:09pm UTC](https://meta.discourse.org/t/writing-directly-to-the-database/300651/18 "2024-03-24T22:09:22Z")

</div>

When the post is created with raw database access, Discourse also seems to rebake it immediately.
