Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Batch Insert #255

Closed
badoet opened this issue Oct 16, 2014 · 162 comments
Closed

Feature Request: Batch Insert #255

badoet opened this issue Oct 16, 2014 · 162 comments

Comments

@badoet
Copy link

badoet commented Oct 16, 2014

pass in []interface{} to batch insert using db.Create([]interface{})

@badoet
Copy link
Author

badoet commented Oct 17, 2014

on the same point, batch row updates would be awesome too.

@jinzhu
Copy link
Member

jinzhu commented Oct 28, 2014

I have thought about it before, but haven't implement it due to can't run callbacks.

@birkirb
Copy link

birkirb commented Nov 19, 2014

👍

@areski
Copy link

areski commented Feb 2, 2015

+1 for Batch insert

@acasanova
Copy link

Is there still no way to accomplish this? I tried building a string of multiple queries and passed it to Exec or Raw but I get errors when using Exec. Raw just seems not to do anything.

INSERT IGNORE INTO img_info (name, filename, path, height,width, mime) VALUES ('a', 'a.jpg.jpg','../../imagedb/thumbs/getty360/a.jpg', '73','110', 'image/jpeg'), ('b', 'b.png.png','../../imagedb/thumbs/getty360/b.png', '73','110', 'image/jpeg'), ('c', 'c.png.png','../../imagedb/thumbs/getty360/c.png', '73','110', 'image/jpeg'), ('d', 'd.png.png','../../imagedb/thumbs/getty360/d.png', '73','110', 'image/jpeg');
INSERT IGNORE INTO pending_uploads (filename, status, created_at) VALUES ('a', 0, '2015-04-23 12:22:37.596460147 -0400 EDT'), ('b', 0, '2015-04-23 12:22:37.596473783 -0400 EDT'), ('c', 0, '2015-04-23 12:22:37.596482969 -0400 EDT'), ('d', 0, '2015-04-23 12:22:37.596489454 -0400 EDT');
INSERT IGNORE INTO metadata (MasterNumber, Prod_Title, Prod_Code, Caption, Keywords,UploadDate) VALUES ('a', 'Getty 360','getty360', '','', '2015-04-23 12:22:37.596323687 -0400 EDT'), ('b', 'Getty 360','getty360', '','', '2015-04-23 12:22:37.596470372 -0400 EDT'), ('c', 'Getty 360','getty360', '','', '2015-04-23 12:22:37.596480429 -0400 EDT'), ('d', 'Getty 360','getty360', '','', '2015-04-23 12:22:37.596487448 -0400 EDT');
&{<nil> Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT IGNORE INTO pending_uploads (filename, status, created_at) VALUES ('a', 0' at line 2 0 map[] <nil> 0xc20805e280 0xc20806aa50 0xc208090d80 0 <nil> <nil> false  map[] map[]}

/Users/acasanova/projects/go/src/com.drleonardo/imagelib/models/services/gettyservice_test.go:117Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT IGNORE INTO pending_uploads (filename, status, created_at) VALUES ('a', 0' at line 2

the actual sql works fine in mysql

image

for now I'll just use individual statements
Any suggestions?

@ilgooz
Copy link

ilgooz commented Jul 2, 2015

+1

@badoet
Copy link
Author

badoet commented Jul 2, 2015

the problem is in the mysql db driver.
i already send a pull request for this capability.
go-sql-driver/mysql#339

@aspcartman
Copy link

+1, any way to do it now?

@derekperkins
Copy link

👍

@ptheunis
Copy link

Waiting for this feature eagerly aswell.

@rodcorsi
Copy link

rodcorsi commented Jun 3, 2016

👍

@viejodecaldas
Copy link

+1 for Batch Inserts

@pjebs
Copy link

pjebs commented Jul 27, 2016

@badoet
Copy link
Author

badoet commented Jul 27, 2016

great news guys!
i have not been following this for a while but i just realized today that the multi statement (batch update exec) capability has been merged to the go-sql-driver/mysql library
go-sql-driver/mysql#411
proudly contributed to this feature.
should be able to turn on this capability by adding &multiStatements=true to the DSN

crystaldust referenced this issue in crystaldust/arkor Aug 2, 2016
In the handler binding, remove the macaron's data structure binding,
since it cannot support []interface{} for now.

In the handler, since the req param is an array, insert the batch data
into database at once by a raw SQL, since gorm currently doesn't support
create multiple records at once. It's a missing feature by the mysql-driver,
which is discussed here:
https://github.com/jinzhu/gorm/issues/255
@benguild
Copy link

benguild commented Sep 1, 2016

One of the things I'd really like is to be able to INSERT many values at once in a single query (for speed):

INSERT INTO table (a, b, c) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)

... etc.

I realize there are some issues here with the fact that (for example) the PrimaryKey/ID wouldn't be returned for multiple rows in this case, and this would require a subsequent SELECT to get that/those. However, that could also just be a disclaimer when using this function in the documentation.

Would be nice to be able to pass [] interface {} to .Create() and do this automatically.

@TylerBrock
Copy link

What do we need to do to start moving on this? I'd like to use gorm for a project but this is a blocker for me.

It seems Like we'd need to trigger the callbacks once for each object in the slice. The tricky part would be error handling and reporting which could either fail immediately or continue processing on errors.

@benguild
Copy link

@TylerBrock It's something you can work around by constructing the queries manually, but that kind of sucks.

@TylerBrock
Copy link

TylerBrock commented Nov 28, 2016

@benguild what would that look like? I'm just starting out with Golang and Gorm but maybe providing a workaround solution example would help a lot of people in this thread out. Would you mind showing us how something like that would be done?

Is it just a single transaction that executes multiple inserts via Gorm or would you use the pg driver directly?

@pjebs
Copy link

pjebs commented Nov 28, 2016

@TylerBrock
Copy link

Yup of course, thanks @pjebs, the SQL syntax I don't have any questions about.

What I was hoping was to see was something where gorm's helpers can be used to construct the statement in a more programmatic fashion but basically the Raw command and SQL builder part of the docs cover it, thanks!

@benguild
Copy link

benguild commented Nov 29, 2016 via email

@sandalwing
Copy link

Is []interface{} a type? Can you have a slice of interfaces?

Wouldn't you want to reflect on the passed interface{} and behave differently if it's slice?

@benguild
Copy link

benguild commented Dec 3, 2016

@sandalwing Yes it is a type... that's what I said here: https://github.com/jinzhu/gorm/issues/255#issuecomment-243997661

Would be nice to be able to pass [] interface {} to .Create() and do this automatically.

... So yeah, that would be a way to do it. However, a .BatchCreate() method would be an alternative considering the caveats with this as I've mentioned in previous comments.

@h1z3y3
Copy link

h1z3y3 commented Sep 27, 2019

+1

@renancloudwalk
Copy link

If anyone ends up here, I had a great experience by integrating https://github.com/t-tiger/gorm-bulk-insert with gorm.

@mcandre
Copy link

mcandre commented Oct 3, 2019

Please implement bulk functions for common queries, including insert, update, and delete. In medium to large applications, batching becomes a first tier priority for maintaining efficient, scalable systems.

@kync
Copy link
Contributor

kync commented Oct 10, 2019

Just to remind you guys: don't forget to supportignore modifiers.

@simon-paris
Copy link

+1

2 similar comments
@sveatlo
Copy link

sveatlo commented Nov 15, 2019

+1

@MaxInertia
Copy link

+1

@bombsimon
Copy link

bombsimon commented Nov 16, 2019

@jinzhu Do you appreciate the +1 or do you keep track of the votes in the original post?

I would really like this and I can help too so I’m watching this issue but I’m kind of against all the +1. If it’s not the desired way according to the maintainers could we try to do a 👍 on the original post instead?

EDIT: I made gorm-bulk similar to the comments above and the one mentioned by t-tiger but with a (in my opinion) more flexible approach letting the end user define their own scope (SQL, and values). It also help you generate code to convert to the required interface slice. It has three default bulk actions bundled as of now (instead of just INSERT INTO) BulkInsert , BulkInsertIgnore and BulkInsertOnDuplicateKeyUpdate but you can define your own. Oh, and it also support gorm:insert_option tag. Not yet stable (no v1 release) .

@sljeff sljeff mentioned this issue Dec 13, 2019
3 tasks
@botastic
Copy link

botastic commented Jan 9, 2020

Hey,
I'd really like to see this feature in the original gorm repo as well. Is there any reason not to add the implementation from @sljeff (provided he agrees to creating a PR)?

@mannharleen
Copy link

Wow! This feature originally open in 2014, +1ed by soooo many and still not closed. Whats stopping this?

@AungATOway
Copy link

+1 for batch insert. When I tried to put []interface{} as parameter to db.Save and get back this panic "reflect: call of reflect.Value.Interface on zero Value"

@jinzhu
Copy link
Member

jinzhu commented Feb 24, 2020

Added its support in v2, so going to close this loooooong issue.

@jinzhu jinzhu closed this as completed Feb 24, 2020
@King-Success
Copy link

Hey, @jinzhu thanks for this. Is v2 ready for use?

@eldilibra
Copy link

@King-Success it's on a branch: https://github.com/jinzhu/gorm/tree/v2_dev

pull it down and give it a whirl!

@King-Success
Copy link

Thanks, @eldilibra

@ivan-marquez
Copy link

@King-Success it's on a branch: https://github.com/jinzhu/gorm/tree/v2_dev

pull it down and give it a whirl!

Hello! which function does the bulk insert in this branch? thanks!

@bombsimon
Copy link

bombsimon commented Mar 7, 2020

Hello! which function does the bulk insert in this branch? thanks!

It's the regular methods you use for single row inserts. Just pass a slice of your type and gorm will create a bulk statement.

type MyType struct {
    Value string
}

func main() {
    // ...
    toInsert := []MyType{
        {Value: "first row"},
        {Value: "second row"},
        {Value: "third row"},
    }

    db.Create(toInsert)
}

Will create a query similar to

INSERT INTO "my_types" ("value") VALUES ('first row'),('second row'),('third row')

@Robihamanto
Copy link

Robihamanto commented Mar 23, 2020

Hello

I can successfully use this func to insert single value :

func (d TaskDB) Create(task *model.Task) (*model.Task, error) {
   err := d.cl.Create(task).Error
   if err != nil {
   	return nil, err
   }
   return task, nil
}

But when I use this, it's become error

func (d TaskDB) Creates(tasks []*model.Task) ([]*model.Task, error) {
	err := d.cl.Create(tasks).Error
	if err != nil {
		return nil, err
	}
	return tasks, nil
}

Anyone can help? thanks

@johnbailon
Copy link

This is what I did:

given these structs

type Item struct {
	Name string
}

type InputItem struct {
	Name string
}

part that bulk inserts a slice InputItem into Item:

var input []InputItem
var items []Item

tx := db.Begin()

defer func() {
	if r := recover(); r != nil {
		tx.Rollback()
	}
}()

if txErr := tx.Error; txErr != nil {
	panic(txErr)
}

for _, i := range input {
	item := Item{Name: i.Name}
	items = append(items, item)
	
	if createErr := tx.Create(&item).Error; createErr != nil {
		panic(createErr)
	}
}

if commitErr := tx.Commit().Error; commitErr != nil { 
	panic(commitErr)
}

@easy-money-sniper
Copy link

how to implement bulk insert with ignore??? like insert ignore into...

@bombsimon
Copy link

@easy-money-sniper For v1, have a look at gorm-bulk and the feature BulkInsertIgnore().

@dark-shade
Copy link

Is it possible to scan back the ids of the bulk inserted records (like in case of a single record)? I tried Scan(&[]recordType{}) and ScanRows(), but they doesn't seem to work ("throws reflection error, "comparing with nil").

@jinzhu
Copy link
Member

jinzhu commented May 27, 2020

Is it possible to scan back the ids of the bulk inserted records (like in case of a single record)? I tried Scan(&[]recordType{}) and ScanRows(), but they doesn't seem to work ("throws reflection error, "comparing with nil").

@dark-shade Yes, will scan back ids

how to implement bulk insert with ignore??? like insert ignore into...

@easy-money-sniper

db.Clauses(clause.OnConflict{DoNothing: true}).Create(&tasks)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests