I have a schema that looks like
Column | Type |
-------------------------------------------------------
message_id | integer |
user_id | integer |
body | text |
created_at | timestamp without time zone |
source | jsonb |
symbols | jsonb[] |
I am trying to use psycopg2 to insert data via psycopg2.Cursor.copy_from() but I am getting numerous issues trying to figure out how a jsonb[] object should be formatted. When I do a straight list of JSON objects, I get an error that looks like
psycopg2.errors.InvalidTextRepresentation: malformed array literal: "[{'id': 13016, 'symbol':
....
DETAIL: "[" must introduce explicitly-specified array dimensions.
I've tried numerous different escapes on the double quotes and curly braces. If I do a json.dumps() on my data, I get the below error.
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type json
DETAIL: Token "'" is invalid.
This error is received from this code snippet
messageData = []
symbols = messageObject["symbols"]
newSymbols = []
for symbol in symbols:
toAppend = symbol
toAppend = refineJSON(json.dumps(symbol))
toAppend = re.sub("{", "\{", toAppend)
toAppend = re.sub("}", "\}", toAppend)
toAppend = re.sub('"', '\\"', toAppend)
newSymbols.append(toAppend)
messageData.append(set(newSymbols))
I'm also open to defining the column as a different type (e.g., text) and then attempting a conversion but I haven't been able to do that either.
messageData is the input to a helper function that calls psycopg2.Cursor.copy_from()
def copy_string_iterator_messages(connection, messages, size: int = 8192) -> None:
with connection.cursor() as cursor:
messages_string_iterator = StringIteratorIO((
'|'.join(map(clean_csv_value, (messageData[0], messageData[1], messageData[2], messageData[3], messageData[4], messageData[5], messageData[6], messageData[7], messageData[8], messageData[9], messageData[10],
messageData[11],
))) + '\n'
for messageData in messages
))
# pp.pprint(messages_string_iterator.read())
cursor.copy_from(messages_string_iterator, 'test', sep='|', size=size)
connection.commit()
EDIT: Based on the input from Mike, I updated the code to use execute_batch() where messages is a list containing messageData for each message.
def insert_execute_batch_iterator_messages(connection, messages, page_size: int = 1000) -> None:
with connection.cursor() as cursor:
iter_messages = ({**message, } for message in messages)
print("inside")
psycopg2.extras.execute_batch(cursor, """
INSERT INTO test VALUES(
%(message_id)s,
%(user_id)s,
%(body)s,
%(created_at)s,
%(source)s::jsonb,
%(symbols)s::jsonb[]
);
""", iter_messages, page_size=page_size)
connection.commit()