How to append a map to a vector in doseq?

I’m using Java Google BigQuery interop ([com.google.cloud/google-cloud-bigquery "2.16.0"]) and I’m trying to convert/return the data as a vector of maps.

The new-map value has data, however, the results data seems empty.

(defn find-by-range [^String start-date ^String end-date]
  {:pre [(some? start-date) (some? end-date)]}
  (let [^String query (find-by-range-sql start-date end-date)
        ^BigQuery big-query (.getService (BigQueryOptions/getDefaultInstance))
        ^QueryJobConfiguration query-config (.build (QueryJobConfiguration/newBuilder query))
        ^TableResult table-result (.query big-query query-config (into-array BigQuery$JobOption []))
        results []]
    (doseq [row (.iterateAll table-result)]
      (let [^String id (.getStringValue (.get row "id"))
            ^String created-at (.getStringValue (.get row "created_at"))
            new-map {:id id :created-at created-at}
            results (into results new-map)]))
    results))

(defn -main
  [& args]
  (let [start-date "2022-07-26T00:00:00"
        end-date "2022-07-26T23:59:59"
        data (find-by-range start-date end-date)]
    (doseq [row data]
      (println row))))

The error:

Syntax error (NullPointerException) compiling at (/private/var/folders/j3/zqjvh17x5hz0d87m0wtkq6cm0000gn/T/form-init16919376317410822441.clj:1:126).
null

What am I doing wrong?

doseq is used for side-effects (only) and returns nil.

Perhaps reduce is what you want here?

The conceptual problem is that scope doesn’t work like this. The inner result is a new binding, not a modification of the outer result.

I’m not sure what .iterateAll returns, but if it’s a sequence, you can use for or map on it. Especially for (but careful: it’s lazy) is almost a drop-in correction for your code:

(for [row (.iterateAll table-result)]
  {:id (.getStringValue (.get row "id"))
   :created-at (.getStringValue (.get row "created_at"))})

With map (again, lazy) or mapv (eager, returns a vector):

(mapv (fn [row]
        {:id (.getStringValue (.get row "id"))
         :created-at (.getStringValue (.get row "created_at"))})
      (.iterateAll table-result))

Thanks for the tip! I’ll research using reduce

Thanks. I’m still learning Clojure and some things are unclear to me. Like adding elements to a vector…

.iterateAll returns an Iterable<FieldValueList>.

mapv worked great, thanks!

It took me a while to discover that I needed to use getValue instead of getStringValue which was raising a NullPointerException. Whereas getValue just returns null if it’s null.