JDBC Driver - Document Collection Metadata

JDBC Driver 3.1 retrieves document collection metadata using the Prism 2.2 document metadata response.

The standard JDBC metadata methods getTables and getColumns describe relational entities. To inspect document collections, unwrap the JDBC connection to an org.polypheny.jdbc.PolyConnection and call getPrismInterfaceClient().searchEntities(namespace, entityNamePattern, timeout). The namespace name is required. The optional entity name filter accepts a SQL-style pattern (% for any sequence, _ for a single character). Pass null to retrieve all entities in the namespace. The timeout is in milliseconds, with 0 meaning no timeout.

Read a collection’s metadata

This example creates a document namespace and two collections on a development instance. Use a fresh namespace name if jdbc_docs_metadata already exists. It filters the entity response using recipe%, reads all document metadata fields, and checks whether the server included a sample.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

import org.polypheny.jdbc.PolyConnection;
import org.polypheny.jdbc.multimodel.PolyStatement;
import org.polypheny.jdbc.dependency.prism.Document;
import org.polypheny.jdbc.dependency.prism.DocumentField;
import org.polypheny.jdbc.dependency.prism.DocumentIndex;
import org.polypheny.jdbc.dependency.prism.Entity;

public class DocumentCollectionMetadata {
    public static void main(String[] args) throws Exception {
        String url = args.length == 0 ? "jdbc:polypheny://localhost:20590" : args[0];
        String namespace = "jdbc_docs_metadata";

        try (Connection connection = DriverManager.getConnection(url, "pa", "");
             Statement sql = connection.createStatement()) {
            sql.executeUpdate("CREATE DOCUMENT NAMESPACE " + namespace);

            PolyConnection poly = connection.unwrap(PolyConnection.class);
            PolyStatement mql = poly.createPolyStatement();
            mql.execute(namespace, "mongo", "db.createCollection(\"recipes\")");
            mql.execute(namespace, "mongo",
                "db.recipes.insertMany([{name: \"Pie\", details: {vegetarian: true}}, {name: \"Soup\"}])");
            mql.execute(namespace, "mongo", "db.createCollection(\"recipes_empty\")");

            for (Entity entity : poly.getPrismInterfaceClient().searchEntities(namespace, "recipe%", 5000)) {
                printCollection(entity);
            }
        }
    }

    static void printCollection(Entity entity) {
        if (!entity.hasDocument()) {
            return;
        }
        Document collection = entity.getDocument();
        System.out.printf("%s.%s%n", collection.getNamespaceName(), collection.getCollectionName());

        for (DocumentField field : collection.getFieldsList()) {
            System.out.printf("  %s: %s (optional: %s)%n",
                field.getFieldPath(), field.getTypeName(), field.getIsOptional());
        }
        if (collection.hasSampleDocumentJson()) {
            System.out.println("  Sample: " + collection.getSampleDocumentJson());
        }
        for (DocumentIndex index : collection.getDocumentIndexesList()) {
            System.out.printf("  Index on %s: %s (unique: %s)%n",
                index.getFieldPath(), index.getIndexType(), index.getUnique());
        }
    }
}

The import paths above are for the published JDBC JAR. It relocates its Prism classes to org.polypheny.jdbc.dependency.prism, so this example only needs the JDBC dependency. The sample contains actual document values. An index entry is printed when the storage adapter reports it.

Interpret the response

Message Java accessor Meaning
Entity hasDocument(), getDocument() Check the entity variant before accessing its collection metadata.
Document getNamespaceName(), getCollectionName() Logical namespace and collection names.
Document getFieldsList() Paths and inferred types from a bounded document sample. An empty collection has no observed fields.
Document hasSampleDocumentJson(), getSampleDocumentJson() Presence flag and JSON text for one sampled document. The sample is absent for an empty collection.
Document getDocumentIndexesList() Indexes reported by the underlying store. The list can be empty if the adapter does not expose index metadata.
DocumentField getFieldPath() Top-level key or nested path such as details.vegetarian. A literal dot is escaped as \. and a literal backslash as \\.
DocumentField getTypeName() Inferred logical type, such as string, int, double, bool, object, array, null, or mixed.
DocumentField getIsOptional() true if the field was missing or null in at least one sampled document.
DocumentIndex getFieldPath(), getIndexType() Indexed path and adapter-reported type, for example btree, hash, wildcard, or text.
DocumentIndex getUnique() Whether the indexed field itself is unique. For compound indexes, each field is reported separately without group-level uniqueness.

Polypheny infers fields from up to 100 documents and reads nested objects up to 32 levels. It reports an array as array without enumerating its elements. Integer and floating point observations of the same field merge to double. Other differing non-null types are reported as mixed. These observations describe the sampled documents and can change as the collection changes.

© Polypheny GmbH. All Rights Reserved.