Upload files

Since v8.0.40

A client can upload arbitrary files to Machbase-Neo via HTTP multipart/form-data encoding. The attached files are stored in the specified directory, and the database keeps the metadata of the file as a JSON string in the column.

Post the column and value in multipart/form-data encoding, where the name of each part should be the column name and the value should be a string representation of the data. Attach the file to a JSON type column with the X-Store-Dir header to specify the directory where the file should be stored. If the specified directory in X-Store-Dir does not exist, the server will create it automatically. The file content will be stored in the directory with a generated unique name in UUID format.

Upload file

This demo assumes the EXAMPLE table has already been created:

CREATE TAG TABLE EXAMPLE(
    NAME     VARCHAR(80)  primary key,
    TIME     DATETIME basetime,
    VALUE    DOUBLE,
    EXTDATA  JSON
)

This example uses curl with the -F option to make a POST request in multipart/form-data encoding.

curl -X POST 'http://127.0.0.1:5654/db/write/EXAMPLE' \
    -F 'NAME=camera-1' \
    -F 'TIME=now' \
    -F 'VALUE=0' \
    -F 'EXTDATA=@./image_file.png;headers="X-Store-Dir: /tmp/store"'

This example uses Visual Studio Code’s REST Client extension.

POST http://127.0.0.1:5654/db/write/EXAMPLE
Content-Type: multipart/form-data; boundary=----Boundary7MA4YWxkTrZu0gW

------Boundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="NAME"

camera-1
------Boundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="TIME"

now
------Boundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="VALUE"

0
------Boundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="EXTDATA"; filename="image_file.png"
X-Store-Dir: /tmp/store
Content-Type: image/png

< ./image_file.png
------Boundary7MA4YWxkTrZu0gW--

X-Store-Dir

The uploaded file content is stored in the directory specified by the X-Store-Dir header, and the file name is based on the ID of the response. The X-Store-Dir header can be included in the part’s header, as shown in the example above, or it can be specified as a top-level header.

${data}
You can use the ${data} variable in the X-Store-Dir path to represent the database home directory. This directory is specified by the --data flag when launching the machbase-neo process, or it defaults to the sub-directory machbase_home under the directory where the machbase-neo executable resides if the --data flag is not used. Please refer to the document about command line flags.

For example, if you set X-Store-Dir: ${data}/store, the uploaded file will be saved in some/path/to/machbase_home/store/file_name_is_ID_of_the_response.

Response Message

Once the file is successfully uploaded, the server responds with the stored file information as shown below.

  • ID : Unique id assigned by the server
  • FN : Original file name
  • SZ : File size
  • CT : Content-Type
  • SD : Stored directory path in the server side
{
  "success": true,
  "reason": "success, 1 record(s) inserted",
  "elapse": "3.772042ms",
  "data": {
    "files": {
      "EXTDATA": {
        "ID": "1ef8a87f-96bd-6576-9ff5-972fa7638db8",
        "FN": "image_file.png",
        "SZ": 12692,
        "CT": "image/png",
        "SD": "/tmp/store"
      }
    }
  }
}

The EXTDATA column in the above example can be accessed as a normal JSON format “string” data which contains the meta information of the uploaded file.

SELECT EXTDATA FROM EXAMPLE
WHERE NAME = 'camera-1' 

Or, use JSON path:

SELECT EXTDATA FROM EXAMPLE
WHERE NAME = 'camera-1'
AND EXTDATA->'$.FN' = 'image_file.png';

The examples that use the SELECT query with the /db/query API:

curl -o - 'http://127.0.0.1:5654/db/query' \
  --data-urlencode "q=select EXTDATA from EXAMPLE\
    where NAME = 'camera-1'"
GET http://127.0.0.1:5654/db/query
  ?q=select EXTDATA from EXAMPLE where NAME = 'camera-1'

Using json path condition with -> notation.

curl -o - 'http://127.0.0.1:5654/db/query' \
  --data-urlencode "q=select EXTDATA from EXAMPLE\
    where NAME = 'camera-1' \
    and EXTDATA->'$.FN' = 'image_file.png'"
GET http://127.0.0.1:5654/db/query
  ?q=select EXTDATA from EXAMPLE where NAME = 'camera-1' and EXTDATA->'$.FN' = 'image_file.png'

The EXTDATA column contains the file information as shown below.

{
  "data": {
    "columns": [ "EXTDATA" ],
    "types": [ "string" ],
    "rows": [
      [
        "{\"ID\":\"1ef8a87f-96bd-6576-9ff5-972fa7638db8\",\"FN\":\"image_file.png\",\"SZ\":12692,\"CT\":\"image/png\",\"SD\":\"/tmp/store\"}"
      ]
    ]
  },
  "success": true,
  "reason": "success",
  "elapse": "843.666µs"
}

Use JSON path to extract specific fields from the JSON type column:

curl -o - http://127.0.0.1:5654/db/query \
  --data-urlencode "format=ndjson"   \
  --data-urlencode "q=SELECT NAME, TIME, EXTDATA->'$.ID' as FID  \
    FROM EXAMPLE WHERE NAME = 'camera-1'"
GET http://127.0.0.1:5654/db/query
    ?format=ndjson
    &q=SELECT NAME, TIME, EXTDATA->'$.ID' as FID  FROM EXAMPLE WHERE NAME = 'camera-1'
{"NAME":"camera-1","TIME":1728950208158594000,"FID":"1ef8a87f-96bd-6576-9ff5-972fa7638db8"}
{"NAME":"camera-1","TIME":1728953137384133000,"FID":"1ef8a8ec-b602-6cac-8fb1-ac9c0c1b981b"}

Read content of the file

The file content can be accessed by the query API:

http://{server_address}/db/query/file/{table}/{column}/{ID}

If the table is TAG table, set tag parameter to improve the server response time:

http://{server_address}/db/query/{tag_table}/{column}/{ID}?tag=camera-1

If the table is a LOG table, the ID is generated based on the time when the record is inserted. For a TAG table, the ID is derived from the base time column of the record.

Since the ID contains timestamp information, Machbase-Neo uses it in the TIME between A and B clause for TAG tables or _ARRIVAL_TIME between A and B for LOG tables to narrow the search range. Note that the timestamp in the ID is NOT exactly the same as the base time or _ARRIVAL_TIME of a LOG table, it is still useful for improving search performance.

HTTP GET

curl -o ./img-download.png \
    http://127.0.0.1:5654/db/query/file/EXAMPLE/EXTDATA/1ef8a87f-96bd-6576-9ff5-972fa7638db8

Use <img> in HTML

<html>
<body>
<img src="http://127.0.0.1:5654/db/query/file/EXAMPLE/EXTDATA/1ef8a87f-96bd-6576-9ff5-972fa7638db8"/>
</body>
</html>

If the table is a TAG table and the tag name is known, use the tag query parameter to improve query performance:

<html>
<body>
<img src="http://127.0.0.1:5654/db/query/file/EXAMPLE/EXTDATA/1ef8a87f-96bd-6576-9ff5-972fa7638db8?tag=camera-1"/>
</body>
</html>

Examples

Javascript

Uploading file in Javascript.

const request = require('request');
const fs = require('fs');

let req = {
    method: 'POST',
    url: 'http://127.0.0.1:5654/db/write/EXAMPLE',
    headers: {"X-Store-Dir": "/tmp/store"},
    formData: {
        NAME: 'camera-1',
        TIME: 'now',
        VALUE: 0,
        EXTDATA:  fs.createReadStream('./image_file.png'), 
    },
};

request(req, function(err, res, body){
    if (err) { console.log(err);
    } else { console.log(body); }
})

Python

Uploading file in Python.

import requests

# Define the URL to which the file will be uploaded
url = 'http://127.0.0.1:5654/db/write/EXAMPLE'

# Path to the image file
file_path = './image_file.png'

# Open the image file in binary mode
with open(file_path, 'rb') as file:
    headers = {'X-Store-Dir': '/tmp/store'}
    data = {'NAME': 'camera-1', 'TIME': 'now', 'VALUE': 0}
    files = {'EXTDATA': ('filename.png', file, 'image/png')}

    # Send the POST request
    response = requests.post(url, data=data, files=files, headers=headers)
    
    # Print the response from the server
    print(response.status_code)
    print(response.text)
Last updated on