Fork me on GitHub
#sql
<
2021-02-15
>
Ovidiu Stoica17:02:10

Ok, after a whole day with this, I need some help. I am trying to bulk insert some values using next-jdb but I keep bumping into this error:

Ovidiu Stoica17:02:27

And here is my code:

(defn insert-multiple-design-versions!
  "Given an array of versions containing the
  :picture key as an array of uri's, extracts the
  pictures from every design-version constructs the
  insertable objects for versions and pictures and inserts them in the correct tables"
  [db versions]
  (let [db-pictures (into [] (flatten (map construct-db-pictures versions)))
        db-versions (into [] (map #(dissoc % :pictures) versions))]
    (jdbc/with-transaction
      [tx db]
      (sql/insert-multi! tx :design-version
                         [:design-id :version-id :name :description] db-versions)
      (sql/insert-multi! tx :picture
                         [:uri :version-id :picture-id]
                         db-pictures))))

Ovidiu Stoica17:02:31

The error throws at the first insert-multi , I assume it has something to do with sql types and I read the docs on next-jdbc/as-type part but I donโ€™t know how to use it. An example data from db-versions is

{:description "Design option description"
 :name        "Design option 2"
 :design-id   "9cd035eb-a4d0-4ce2-ae75-b3b3cdcb76ed"
 :version-id  "4e901694-4279-4722-bfea-8fd841f772aa"}
And they are all strings

Ovidiu Stoica17:02:50

Also, I am a beginner with clojure so any feedback on my code is greatly apreciated ๐Ÿ˜„

seancorfield18:02:24

What are you passing in as versions?

seancorfield18:02:39

The error suggests you are passing MapEntry values so I suspect you are passing a hash map where a sequence of hash maps is expected @ovidiu.stoica1094

Ovidiu Stoica18:02:16

So you mean I am passing a map instead of an array

Ovidiu Stoica18:02:35

That does make sense. Let me debug a bit with this in mind

seancorfield18:02:43

insert-multi! expects a connection, a table, a list of column names and list of row values -- a list of lists (or a vector of vectors). (into [] (flatten ..)) is going to produce a single long sequence instead of a sequence of sequences so that's def. going to fail for the second insert (of db-pictures).

seancorfield18:02:35

It looks like versions is a sequence of hash maps so db-versions will also be a sequence of hash maps, so that is also not acceptable to insert-multi!

Ovidiu Stoica18:02:21

Yes I was passing a list of maps with key-value pairs instead of a list of lists with only the values

seancorfield18:02:31

juxt would be very helpful here: (juxt :design-id :version-id :name :description) produces a function that, when applied to a hash map, will pull out those values in the specified order (hash maps are inherently unordered).

seancorfield18:02:06

So I think you want (map (juxt :the :keys :you :want) list-of-hash-maps)

Ovidiu Stoica18:02:14

I was actually looking for something exactly like that earlier ๐Ÿ˜ฎ

seancorfield18:02:27

flatten is almost never the right answer to any problem ๐Ÿ™‚

Ovidiu Stoica18:02:43

Iโ€™ll make sure to remember ๐Ÿ˜„

Ovidiu Stoica18:02:43

Thank you so much, @seancorfield and also, since I have a chance to talk to you, thank you so much for next.jdbc . It has been a great help for me and Iโ€™m definitely learning a lot from how you wrote the code in the lib. Iโ€™m browsing through it from time to time

seancorfield18:02:02

I'd probably do something like this:

(let [pic-cols [:design-id :version-id :name :description]
  (sql/insert-multi! ds :design-version pic-cols (map (apply juxt pic-cols) pictures)))

seancorfield18:02:11

(off the top of my head)

Ovidiu Stoica18:02:57

That is great. Easy to understand