Using the Document Store
This page explains everything you need to know when developing a Cloud Function that makes use of the Document Store.
What is the Document Store?
A Document Store is a database that can store data that you would want your Cloud Function to keep over time. For example, if you want your Cloud Function to register and store what actions each user takes, you could store this in the document store. Each Cloud Function has the following characteristics in relation to the Document Store:
- It has its own, separate store and can only read and write data to its own store.
- It can only access a single store, meaning that a DB collection is not shareable among Cloud Functions.
- The document store can accept any data in JSON format. This means that if you store documents in the store, for example via a Cloud Function, you must ensure that your data can be converted to JSON.
- A local document store is automatically provided for you when you develop your Cloud Function.
Store Availability
- The store is not available from the developer web form (see the picture in this section), but it can be called via a Cloud Function by using the Function field as explained in the article.
- When developing, the local store is reset at each restart.
- The store is only available from
ixoncdkingress>=0.0.10
When starting your Cloud Function, you should see the following messages:
ixoncdkingress - INFO - Starting DocumentDB server
ixoncdkingress - INFO - DocumentDB server started successfully
These messages show that the document store has successfully started and can be used in your Cloud Function.
How to use the DocumentDBClient
The DocumentDBClient
can be extracted from the Cloud Function Context by accessing document_db_client
from the context:
from ixoncdkingress.function.context import FunctionContext
@FunctionContext.expose
def document_test_entrypoint(context: FunctionContext):
print(context.document_db_client)
From here you can perform a variety of functions to create, read, update and delete documents in your document store.
NullabilityAs mentioned above, the store is not always available. So the
document_db_client
can beNone
. Be sure to check for this when developing your Cloud Function.The store can be
None
in these scenarios:
- The
document_db_client
may beNone
when running the Cloud Function in development mode and using the local debug form without specifying a company. A company ID and a company name are the only required fields:If the DocumentDBClient is available, you will see something like
<DocumentDBClient company=4444-5555-3333-1111-9999,>
printed in the console.
- When running the cloud function in development mode, a MongoDB container is automatically spun up. This can fail and if the MongoDB container fails to boot or if there is any other reason why the local function cannot connect to the container, the store will be
None
.
TimezonesAll dates, times and datetimes will be returned as naive objects (i.e. unaware of timezone) by the DocumentDBClient. All times and datetimes are stored in UTC and should be interpreted as such. When storing times and datetimes in Document Store, always use UTC.
The DocumentDBClient
contains the following functions:
Function | Parameters | Description | Minimal ixoncdkingress version |
---|---|---|---|
insert_one | document: Dict | Inserts a single document into the store | 0.0.10 |
insert_many | document: Iterable[Dict] | Inserts multiple documents into the store | 0.0.10 |
update_one | filter_map: Mapping, update: Mapping | Updates a single document from the store | 0.0.10 |
update_many | filter_map: Mapping, update: Mapping | Updates multiple documents from the store | 0.0.10 |
delete_one | filter_map: Mapping | Removes one document from the store | 0.0.10 |
delete_many | filter_map: Mapping | Removes multiple documents from the store | 0.0.10 |
find_one | filter_map: Mapping | Same as find but only returns a single document | 0.0.10 |
find | filter_map: Mapping | Perform a query on the database with a specific filter | 0.0.10 |
The filter_map
can be used to find specific documents by their keys, while the update
Mapping can be used to update specific keys of one or more documents. Here is an example of some of the functions you can use:
from typing import Any, List, TypedDict
from bson.json_util import dumps
from ixoncdkingress.function.context import FunctionContext
@FunctionContext.expose
def document_find_text(context: FunctionContext, id: int) -> dict[str, Any] | None:
# Find one document by its ID
return dumps(context.document_db_client.find_one(filter_map={'id': id}))
@FunctionContext.expose
def document_find_all(context: FunctionContext) -> str:
# Find all documents in the store
return dumps(context.document_db_client.find())
@FunctionContext.expose
def document_add_or_update_text(context: FunctionContext, id: int, text: str) -> None:
found = document_find_text(context, id)
# If document already exists update the text by the ID
# otherwise insert a new document
if found is not None:
context.document_db_client.update_one({'id': id}, {'$set': {'text': text}})
else:
context.document_db_client.insert_one({'id': id, 'text': text})
class Document(TypedDict):
id: int
text: str
@FunctionContext.expose
def document_insert_many(context: FunctionContext, documents: List[Document]) -> None:
# Insert the documents
context.document_db_client.insert_many(documents)
<script>
import { onMount } from "svelte";
export let context; // Assuming context is passed in as a prop for backend interactions
let client; // Initialize the client for backend communication
// Modular function to call backend functions
async function callBackendFunction(functionName, parameters = {}) {
try {
const response = await client.call(functionName, parameters);
console.log(response);
return response; // Return response for further processing
} catch (error) {
console.error(`Error calling ${functionName}:`, error);
}
}
onMount(() => {
client = context.createBackendComponentClient();
// Sequentially call backend functions with await inside async function
(async () => {
await callBackendFunction("functions.document_find_all");
await callBackendFunction("functions.document_add_or_update_text", {
id: 0, // Example ID, ensuring it's an integer to match Python backend
text: "Hello, World!",
});
await callBackendFunction("functions.document_find_all");
await callBackendFunction("functions.document_find_text", {
id: 0,
});
await callBackendFunction("functions.document_insert_many", {
documents: [
{ id: 1, text: "First text" },
{ id: 2, text: "Second text" },
],
});
await callBackendFunction("functions.document_find_all");
})();
});
</script>
<main>
<h1>Frontend Component</h1>
<p>Open the terminal to see the results of the backend calls.</p>
</main>
From here, you can play around with inserting, reading, updating and deleting documents.
Inspecting the Document Store contents
You can easily inspect the contents of you local Document Store using MongoDB Compass GUI or MongoDB For VS Code.
Updated 2 days ago
To read more about advanced document querying please read: