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 its own separate store and can only read and write data to its own store. A Cloud Function can only access a single store. The document store can accept any data in JSON format. This means that if you store documents in the store, 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 isn't available from the developer web form.
  • 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.

🚧

Nullability

As mentioned above, the store is not always available. So the document_db_client can be None. Be sure to check for this when developing your Cloud Function.

❗️

Timezones

All 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:

FunctionParametersDescriptionMinimal ixoncdkingress version
insert_onedocument: DictInserts a single document into the store0.0.10
insert_manydocument: Iterable[Dict]Inserts multiple documents into the store0.0.10
update_onefilter_map: Mapping, update: MappingUpdates a single document from the store0.0.10
update_manyfilter_map: Mapping, update: MappingUpdates multiple documents from the store0.0.10
delete_onefilter_map: MappingRemoves one document from the store0.0.10
delete_manyfilter_map: MappingRemoves multiple documents from the store0.0.10
find_onefilter_map: MappingSame as find but only returns a single document0.0.10
findfilter_map: MappingPerform a query on the database with a specific filter0.0.10
switch_collectioncollection_name: Optional[str]Switch to another collection. When collection_name is None or an empty string, the default collection is used0.0.17

🚧

Multiple collections

The document store has one collection by default. When you want to use multiple collections, please send an email to [email protected] to have them configured and provide the following details:

  • The Cloud Function public ID.
  • The name(s) of the collection(s) you want to use.

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.


What’s Next

To read more about advanced document querying please read: