Python interface to Oracle Database with thin and thick connectivity modes
—
Simple Oracle Document Access (SODA) provides a NoSQL-style API for working with JSON documents in Oracle Database. SODA allows applications to create, read, update, and delete JSON documents stored in Oracle collections without writing SQL. The API provides document operations, filtering, indexing, and metadata management for JSON document storage.
The main entry point for SODA operations, accessible through a database connection.
# Access SODA database through connection
def getSodaDatabase(self) -> SodaDatabase: ...
class SodaDatabase:
def createCollection(self, name: str, metadata: Union[str, dict] = None, mapMode: bool = False) -> SodaCollection:
"""
Creates a SODA collection with the given name and returns a new SODA
collection object. If you try to create a collection, and a collection
with the same name and metadata already exists, then that existing
collection is opened without error.
Parameters:
- name (str): Name of the collection to create
- metadata (Union[str, dict]): JSON metadata specifying collection configuration
- mapMode (bool): If True, map to existing table instead of creating new table
Returns:
SodaCollection: New or existing collection object
"""
def createDocument(self, content: Any, key: str = None, mediaType: str = "application/json") -> SodaDocument:
"""
Creates a SODA document usable for SODA write operations. You only need
to use this method if your collection requires client-assigned keys or
has non-JSON content.
Parameters:
- content (Any): Document content (dict, list, str, or bytes)
- key (str): Client-assigned key (if required by collection)
- mediaType (str): MIME type for non-JSON documents
Returns:
SodaDocument: New document object
"""
def getCollectionNames(self, startName: str = None, limit: int = 0) -> List[str]:
"""
Returns a list of the names of collections in the database that match
the criteria, in alphabetical order.
Parameters:
- startName (str): Starting collection name for filtering
- limit (int): Maximum number of names to return (0 for no limit)
Returns:
List[str]: Collection names in alphabetical order
"""
def openCollection(self, name: str) -> SodaCollection:
"""
Opens an existing collection with the given name and returns a new SODA
collection object. If a collection with that name does not exist, None
is returned.
Parameters:
- name (str): Name of the collection to open
Returns:
SodaCollection: Collection object or None if not found
"""Represents a collection of JSON documents with methods for CRUD operations, indexing, and metadata access.
class SodaCollection:
# Properties
name: str # Read-only collection name
metadata: dict # Read-only collection metadata
def createIndex(self, spec: Union[dict, str]) -> None:
"""
Creates an index on a SODA collection. The spec is expected to be a
dictionary or a JSON-encoded string.
Parameters:
- spec (Union[dict, str]): Index specification as dict or JSON string
"""
def drop(self) -> bool:
"""
Drops the collection from the database, if it exists. Note that if the
collection was created with mapMode set to True the underlying table
will not be dropped.
Returns:
bool: True if collection was dropped, False if it didn't exist
"""
def dropIndex(self, name: str, force: bool = False) -> bool:
"""
Drops the index with the specified name, if it exists.
Parameters:
- name (str): Name of the index to drop
- force (bool): Force dropping of spatial/search indexes
Returns:
bool: True if index was dropped, False if it didn't exist
"""
def find(self) -> SodaOperation:
"""
This method is used to begin an operation that will act upon documents
in the collection. It creates and returns a SodaOperation object which
is used to specify the criteria and the operation that will be
performed on the documents that match that criteria.
Returns:
SodaOperation: Operation builder for chaining criteria
"""
def getDataGuide(self) -> SodaDocument:
"""
Returns a SODA document object containing property names, data types
and lengths inferred from the JSON documents in the collection. It can
be useful for exploring the schema of a collection.
Returns:
SodaDocument: Data guide document or None if no documents exist
"""
def insertMany(self, docs: list) -> None:
"""
Inserts a list of documents into the collection at one time. Each of
the input documents can be a dictionary or list or an existing SODA
document object.
Parameters:
- docs (list): List of documents to insert
"""
def insertManyAndGet(self, docs: list, hint: str = None) -> list:
"""
Similarly to insertMany() this method inserts a list of documents into
the collection at one time. The only difference is that it returns a
list of SODA Document objects.
Parameters:
- docs (list): List of documents to insert
- hint (str): SQL hint for database processing
Returns:
list: List of inserted SodaDocument objects
"""
def insertOne(self, doc: Any) -> None:
"""
Inserts a given document into the collection. The input document can be
a dictionary or list or an existing SODA document object.
Parameters:
- doc (Any): Document to insert
"""
def insertOneAndGet(self, doc: Any, hint: str = None) -> SodaDocument:
"""
Similarly to insertOne() this method inserts a given document into the
collection. The only difference is that it returns a SODA Document
object.
Parameters:
- doc (Any): Document to insert
- hint (str): SQL hint for database processing
Returns:
SodaDocument: Inserted document object
"""
def listIndexes(self) -> list:
"""
Return a list of indexes associated with the collection.
Returns:
list: List of index specifications as dictionaries
"""
def save(self, doc: Any) -> None:
"""
Saves a document into the collection. This method is equivalent to
insertOne() except that if client-assigned keys are used, and the
document with the specified key already exists in the collection, it
will be replaced with the input document.
Parameters:
- doc (Any): Document to save
"""
def saveAndGet(self, doc: Any, hint: str = None) -> SodaDocument:
"""
Saves a document into the collection. This method is equivalent to
insertOneAndGet() except that if client-assigned keys are used, and the
document with the specified key already exists in the collection, it
will be replaced with the input document.
Parameters:
- doc (Any): Document to save
- hint (str): SQL hint for database processing
Returns:
SodaDocument: Saved document object
"""
def truncate(self) -> None:
"""
Removes all of the documents in the collection, similarly to what is
done for rows in a table by the TRUNCATE TABLE statement.
"""Represents a single JSON document with content, metadata, and access methods.
class SodaDocument:
# Properties
createdOn: str # Read-only creation timestamp in ISO 8601 format
key: str # Read-only unique document key
lastModified: str # Read-only last modified timestamp in ISO 8601 format
mediaType: str # Read-only media type (usually "application/json")
version: str # Read-only document version
def getContent(self) -> Union[dict, list]:
"""
Returns the content of the document as a dictionary or list. This
method assumes that the content is application/json and will raise an
exception if this is not the case.
Returns:
Union[dict, list]: Parsed JSON content or None if no content
"""
def getContentAsBytes(self) -> bytes:
"""
Returns the content of the document as a bytes object. If there is no
content, however, None will be returned.
Returns:
bytes: Raw document content or None if no content
"""
def getContentAsString(self) -> str:
"""
Returns the content of the document as a string. If the document
encoding is not known, UTF-8 will be used.
Returns:
str: Document content as string or None if no content
"""Iterator for streaming access to large result sets of documents.
class SodaDocCursor:
def __iter__(self) -> SodaDocCursor: ...
def __next__(self) -> SodaDocument: ...
def close(self) -> None:
"""
Close the cursor now, rather than whenever __del__ is called. The
cursor will be unusable from this point forward; an Error exception
will be raised if any operation is attempted with the cursor.
"""Fluent interface for building complex queries and operations on documents.
class SodaOperation:
def count(self) -> int:
"""
Returns a count of the number of documents in the collection that match
the criteria. If skip() or limit() were called on this object, an
exception is raised.
Returns:
int: Number of matching documents
"""
def fetchArraySize(self, value: int) -> SodaOperation:
"""
This is a tuning method to specify the number of documents that are
internally fetched in batches by calls to getCursor() and
getDocuments().
Parameters:
- value (int): Batch size (0 for default of 100)
Returns:
SodaOperation: Self for method chaining
"""
def filter(self, value: Union[dict, str]) -> SodaOperation:
"""
Sets a filter specification for complex document queries and ordering
of JSON documents. Filter specifications must be provided as a
dictionary or JSON-encoded string.
Parameters:
- value (Union[dict, str]): Filter specification
Returns:
SodaOperation: Self for method chaining
"""
def getCursor(self) -> SodaDocCursor:
"""
Returns a SodaDocCursor object that can be used to iterate over the
documents that match the criteria.
Returns:
SodaDocCursor: Cursor for iterating documents
"""
def getDocuments(self) -> list:
"""
Returns a list of SodaDocument objects that match the criteria.
Returns:
list: List of matching documents
"""
def getOne(self) -> Union[SodaDocument, None]:
"""
Returns a single SodaDocument object that matches the criteria. Note
that if multiple documents match the criteria only the first one is
returned.
Returns:
Union[SodaDocument, None]: First matching document or None
"""
def hint(self, value: str) -> SodaOperation:
"""
Specifies a hint that will be provided to the SODA operation when it is
performed. This is expected to be a string in the same format as SQL
hints but without any comment characters.
Parameters:
- value (str): SQL hint string
Returns:
SodaOperation: Self for method chaining
"""
def lock(self) -> SodaOperation:
"""
Specifies whether the documents fetched from the collection should be
locked (equivalent to SQL "select for update").
Returns:
SodaOperation: Self for method chaining
"""
def key(self, value: str) -> SodaOperation:
"""
Specifies that the document with the specified key should be returned.
This causes any previous calls made to this method and keys() to be
ignored.
Parameters:
- value (str): Document key to match
Returns:
SodaOperation: Self for method chaining
"""
def keys(self, value: list) -> SodaOperation:
"""
Specifies that documents that match the keys found in the supplied
sequence should be returned. This causes any previous calls made to
this method and key() to be ignored.
Parameters:
- value (list): List of document keys to match
Returns:
SodaOperation: Self for method chaining
"""
def limit(self, value: int) -> SodaOperation:
"""
Specifies that only the specified number of documents should be
returned. This method is only usable for read operations such as
getCursor() and getDocuments().
Parameters:
- value (int): Maximum number of documents to return
Returns:
SodaOperation: Self for method chaining
"""
def remove(self) -> int:
"""
Removes all of the documents in the collection that match the criteria.
The number of documents that have been removed is returned.
Returns:
int: Number of documents removed
"""
def replaceOne(self, doc: Any) -> bool:
"""
Replaces a single document in the collection with the specified
document. The input document can be a dictionary or list or an existing
SODA document object.
Parameters:
- doc (Any): Replacement document
Returns:
bool: True if a document was replaced, False otherwise
"""
def replaceOneAndGet(self, doc: Any) -> SodaDocument:
"""
Similarly to replaceOne(), this method replaces a single document in
the collection with the specified document. The only difference is that
it returns a SodaDocument object.
Parameters:
- doc (Any): Replacement document
Returns:
SodaDocument: Replaced document object
"""
def skip(self, value: int) -> SodaOperation:
"""
Specifies the number of documents that match the other criteria that
will be skipped. This method is only usable for read operations such as
getCursor() and getDocuments().
Parameters:
- value (int): Number of documents to skip
Returns:
SodaOperation: Self for method chaining
"""
def version(self, value: str) -> SodaOperation:
"""
Specifies that documents with the specified version should be returned.
Typically this is used with key() to implement optimistic locking.
Parameters:
- value (str): Document version to match
Returns:
SodaOperation: Self for method chaining
"""import oracledb
# Basic SODA usage
with oracledb.connect(user="user", password="pwd", dsn="localhost/orclpdb") as connection:
# Get SODA database
soda_db = connection.getSodaDatabase()
# Create or open a collection
collection = soda_db.createCollection("employees")
# Insert a document
doc_content = {"name": "John Doe", "department": "Engineering", "salary": 75000}
collection.insertOne(doc_content)
# Query documents
documents = collection.find().filter({"department": "Engineering"}).getDocuments()
for doc in documents:
print(f"Employee: {doc.getContent()}")
# Update a document
result = collection.find().key("some_key").replaceOne({"name": "Jane Doe", "department": "Marketing"})
# Remove documents
removed_count = collection.find().filter({"salary": {"$lt": 50000}}).remove()
print(f"Removed {removed_count} documents")Install with Tessl CLI
npx tessl i tessl/pypi-oracledb