Blackhole Consulting

Insights on Automation, Data Engineering & Internal Tools

Created: 2022-07-11

Building a Schemaless All-Purpose Document Viewer with Retool

Created: 2022-07-11

Client needed a MongoDB viewer to access any document across many collections, without write access.

Challenges

Solution

Our client had all of its data stored in various schemas in a MongoDB database. In order to provide easy access for support agents, the client needed an application where the user could look up any document of any collection. The challenge: inherently schemaless, the client wanted to have a viewer for all collections, no matter the schema or the type. The desired functionality was close to what was provided by MongoDB Compass but without the user having either privileged access or a chance to edit the content of a document.

One of the limitations to the MongoDB integration in Retool concerns listing collections. At the point of writing this post, collections had to be called individually in each query.

To provide the required functionality, we created an ad-hoc structure within a JSON editor object in Retool. Said implementation would have the benefit of supporting changes even in the future; if a new collection was to be added to a database, the client would simply add that collection to the schema in the Configuration part of the app.

The Document Viewer in its final form

The Configuration tab contains a JSON explorer / editor component which hosts the DB structure following this schema:

{
  "database1": ["coll1", "coll2"],
  "database2": ["coll3", "coll4"]
}

Database Structure

For each database we needed to create a query to findDocuments and to listDocuments - at the time of writing this post, the client had three databases meaning we needed 3x2 = 6 very similar queries to make use of the above technique.

findDocuments query

Using the ternary operator in JS, we can then render the required data readily in a similar fashion.

Similarly to the doc_table implementation, we extract the content of each document inside a JSON explorer aptly called document_view:

The Payload content here is stored in the 'data' member of the document, so we unravel the content using lodash for the Payload JSON explorer component:

Document Viewer

_.has(document_view.value['0'], 'data') ? document_view.value['0'].data : ...

The payload renderer then just takes the value of payload_view.