Skip to content
Advertisement

How to pass an SQL function on bulk insert query in node

I have to execute an INSERT INTO query using mysql or mysql2 in node.js
The values passed into the query utilizes a spatial geometry function ST_GeomFromGeoJSON() on geoMap column which is of type GEOMETRY.

Here is the simplified code:

const insertQuery = `INSERT INTO maps (name, geoMap) VALUES ?`;
const insertData = [];

geoMapList.forEach((geoMap) => {
  insertData.push([
    geoMap.name,
    `ST_GeomFromGeoJSON(${JSON.stringify(geoMap.map)}, 2)`
  ]);
});

this.connection.query(insertQuery, [insertData]);

The above code does not work and throws the error
Cannot get geometry object from data you send to the GEOMETRY field

I believe this is because the ST_GeomFromGeoJSON() is not parsed as a function but as a string by MySQL.

How can this be resolved?

Advertisement

Answer

You can’t put MySQL function calls in the parameter array, that data is all treated as literals.

Call the function in the SQL, with the JSON string as its parameter.

I don’t think you can use node-mysql‘s bulk-insert for this, though, so you’ll need to insert each row separately.

const insertQuery = `INSERT INTO maps(name, geoMap) VALUES (?, ST_GeomFromGeoJSON(?))`
geoMapList.forEach((geomap) => 
    this.connection.query(insertQuery, [geomap.name, JSON.stringify(geomap.map)])
);

To avoid calling query() thousands of times, you can put multiple values lists in the query.

const values = Array(geoMapList.length).fill('(?, ST_GeomFromGeoJSON(?))).join(',');
const insertQuery = `INSERT INTO maps(name, geoMap) VALUES ${values}`;
const params = geoMapList.flatMap(({name, map}) => [name, JSON.stringify(map)]);
this.connection.query(insertquery, params);

Since this will create a very long INSERT query, make sure you increase the MySQL max_allowed_packet setting. You can also split geoMapList into smaller batches, rather than doing everything in a single query.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement