Em 04-10-2013 19:13, Jeremy Evans escreveu:
On Friday, October 4, 2013 2:36:33 PM UTC-7, Rodrigo Rosenfeld Rosas wrote:

    It would be great if this would work the way most would expect it
    to behave:

    ids = MyModel.dataset.returning(:id).import [:a, :b], [[1, 2], [3,
    4]] # => [id1, id2]

    Could you please consider this for some future version?


Looks like it isn't currently documented (I'll fix that), but you can use the :return=>:primary_key option to do so starting in Sequel 3.31.0.

Great, good to know. I'll change my manual import statement back to using #import with those options on Monday.


Most people using #import/#multi_insert probably don't care about the inserted ids, and using the option can make things slower, which is why it doesn't operate that way by default.

I totally understand and I was even wondering yesterday if the returning clause (even "returning null") could slow down the import statement a little, even if you are not fetching the returned values...


Let me try to illustrate my confusing database design and application goals to something simpler (although I can't see anyone actually mapping a music sheet to a RDMS this way :P ), so that I could explain why the returning clause is useful for my situation.

Suppose you want to import a song score from some JSON, where the score contains measures, which contains notes:

tables:

- song_scores(id, title)
- measures(id, score_id, position, cleff)
- notes(id, measure_id, pitch, duration)

You could even scale the problem if you want to import a songbook by adding a songbook_id to song_score.

I realize this model is rather incomplete but it doesn't matter as you wouldn't want to represent a music sheet this way anyway :) Also, the notes should have a position column too, but let's ignore that...

So, suppose your import procedure accepts a JSON like this (mine is actually more compact, but it shouldn't matter):

{
  "title": "Naquele Tempo",
  "measures": [
    {
        "cleff": "g",
        "notes": [
            {"pitch": "C", duration: 2},
            ...
        ]
    },
    ...
  ]
}

In my application I actually have to merge this JSON, not only insert in the database. So how would you design such a batch merge strategy on PostgreSQL for something like the above case?

Here's my strategy (I actually got it working yesterday, so I know it works):

In our application, there's something like a unique constraint over measures(score_id, position) which complicates it even more, so I decided to simplify it.

To keep it simpler I decided to delete all measures and notes for the song if it exists (take the title as unique, for instance, but in my case it's actually an unique foreign key) and start the procedure from there.

So basically, this is how it works in a conceptual level:

1 - start a transaction
2 - lock tables song_scores, measures and notes for exclusive access
3 - delete all records in all those tables for the imported score (in my application I don't have to delete the first level and will apply a merge strategy instead, but what I'm trying to do here is to explain how I'm using the "returning id" values to simplify my import procedure) 4 - generate an array with the values for measures, including the position based on some each_with_index block 5 - import the measures and store their ids. They will be in the same order of the previous array
6 - use the returned ids to be able to import the notes
7 - commit the transaction

Let me detail a bit how 4 works:

score_id = find_or_create_score.id
measures = []
all_notes = []
json['measures'].each_with_index do |measure, position|
  measures << [score_id, position, measure['cleff']]
all_notes << measure['notes'] # this is required in my cases because I'll skip some values earlier in the loop for some conditions
end

measure_ids = DB[:measures].import [:score_id, :position, :cleff], measures, return: :primary_key
notes_values = []
all_notes.each_with_index do |notes, i|
  measure_id = measure_ids[i]
  notes.each {|n| notes_values << [measure_id, n['pitch], n['duration']] }
end

DB[:notes].import [:measure_id, :pitch, :duration], notes_values

Wow, I wrote way more I had originally planned to :P

Hopefully you understand how returning the ids simplified my import procedure a lot :)

Have a nice weekend!

Cheers,
Rodrigo.

--
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to