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

INSERT complex types into a PostgreSQL table. #25

Closed
dbauszus-glx opened this issue Aug 2, 2019 · 3 comments
Closed

INSERT complex types into a PostgreSQL table. #25

dbauszus-glx opened this issue Aug 2, 2019 · 3 comments

Comments

@dbauszus-glx
Copy link

I am able to select and insert text and numbers into a PostgreSQL table, but anything more complex fails.

For example this template literal produces completely legit SQL which can copy into the command line for execution.

    db.query(sql`
        
    INSERT INTO dev.jack_wolfskin (id, city, store, lat, lng, geom)
    VALUES (
        ${parseInt(store.id)},
        '${store.city}',
        '${JSON.stringify(store)}',
        ${parseFloat(store.lat)},
        ${parseFloat(store.lng)},
        ${'ST_SetSRID(ST_Point(' + parseFloat(store.lng) + ',' + parseFloat(store.lat) + '),4326)'}
    )
    
    `)

The table schema is as follows:

create table if not exists dev.my_table
(
	id integer,
	city text,
	store json,
	lat double precision,
	lng double precision,
	geom geometry(Point, 4326)

);

I have tried to break it down but I have no clue how to insert json type or geometry type generated from a function.

This works pretty well node postgres so there must be something in the atdatabase wrapper which I don't understand.

It would be great if you can provide an example as I would like to do more testing with this product.

@dbauszus-glx
Copy link
Author

Here is the full code with @database/pg

const connect = require('@databases/pg');

const sql = require('@databases/sql');

const db = connect(process.env.pg_connection);

db.query(sql`

SELECT
    city_name,
    st_x(geom_p_4326) as lng,
    st_y(geom_p_4326) as lat
FROM dev.world_cities limit 10;

`)
.then(
  results => processResults(results),
  err => console.error(err)
);

function processResults(results) {

    results.forEach(async row => {
        const response = await require('node-fetch')(`https://www.jack-wolfskin.co.uk/on/demandware.store/Sites-JackWolfskin_UK-Site/en_GB/Store-FindStores?lat=${row.lat}&lng=${row.lng}`);
        const json = await response.json();

        if (!json.stores.length) return;

        json.stores.forEach(store => processStore(store));
    });
}

function processStore(store){

    db.query(sql`
        
    INSERT INTO dev.jack_wolfskin (id, city, store, lat, lng, geom)
    VALUES (
        ${parseInt(store.id)},
        '${store.city}',
        '${JSON.stringify(store)}',
        ${parseFloat(store.lat)},
        ${parseFloat(store.lng)},
        ${'ST_SetSRID(ST_Point(' + parseFloat(store.lng) + ',' + parseFloat(store.lat) + '),4326)'}
    )
    
    `)
    .then(
        results => console.log(results),
        err => console.error(err)
    );
}

This fails on the insert statement with all kinds of errors.

And here is the same script using the pg module.

const db = new require('pg').Pool({
    connectionString: process.env.pg_connection,
    statement_timeout: 10000
  });


db.query(`

SELECT
    city_name,
    st_x(geom_p_4326) as lng,
    st_y(geom_p_4326) as lat
FROM dev.world_cities limit 10;

`)
.then(
  results => processResults(results),
  err => console.error(err)
);

function processResults(results) {

    results.rows.forEach(async row => {
        const response = await require('node-fetch')(`https://www.jack-wolfskin.co.uk/on/demandware.store/Sites-JackWolfskin_UK-Site/en_GB/Store-FindStores?lat=${row.lat}&lng=${row.lng}`);
        const json = await response.json();

        if (!json.stores.length) return;

        json.stores.forEach(store => processStore(store));
    });
}



function processStore(store){

    db.query(`
        
    INSERT INTO dev.jack_wolfskin (id, city, store, lat, lng, geom)
    VALUES (
        ${parseInt(store.id)},
        '${store.city}',
        '${JSON.stringify(store)}',
        ${parseFloat(store.lat)},
        ${parseFloat(store.lng)},
        ${'ST_SetSRID(ST_Point(' + parseFloat(store.lng) + ',' + parseFloat(store.lat) + '),4326)'}
    )
    
    `)
    .then(
        results => console.log(results),
        err => console.error(err)
    );
}

This works A-OK.

@ForbesLindesay
Copy link
Owner

ForbesLindesay commented Aug 2, 2019

I think you want something like:

    db.query(sql`
        
    INSERT INTO dev.jack_wolfskin (id, city, store, lat, lng, geom)
    VALUES (
        ${parseInt(store.id)},
        ${store.city},
        ${store},
        ${parseFloat(store.lat)},
        ${parseFloat(store.lng)},
        ST_SetSRID(ST_Point(${parseFloat(store.lng)}, ${parseFloat(store.lat)}), 4326)'
    )
    
    `)

There are three problems with your original code:

  1. you're wrapping your strings in quotes, which you would need to do if they were being added directly to the SQL string, but they're not. They are being put into the SQL as values, so you can just trust to the fact that they are strings.
  2. you've set the type of store to json, but what you're actually storing is a string (i.e. the result of calling JSON.stringify. I think, if I remember correctly, this will result in postgres double JSON stringifying the value. Just pass the actual value and trust to pg to handle it.
  3. The value isn't the string ST_SetSRID(... the values are the three numbers. The rest is SQL syntax, so it needs to be in template literal land, not JavaScript string land.

I hope this helps.

@dbauszus-glx
Copy link
Author

Thanks Forbes that works perfectly fine.

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

No branches or pull requests

2 participants