This page describes Calíope 1.7, the version I am building right now. 1.6 is on the App Store for the Mac, iPad, iPhone, Apple Watch, Apple TV and Apple Vision Pro. The changelog says which version each feature landed in.

Adds an “Open in Calíope” button to every topic. It only works with the app installed.

MongoDB

Browse collections and documents

How to move around a MongoDB server’s databases, collections and documents.

Where it is: Workspace › Tools › Collections

The browser lists the chosen database’s collections on the left and their documents on the right, as collapsible trees.

A document is not a row: two neighbouring documents may share no field at all, which is why there is no column grid. Each value shows its type — ObjectId, decimal128, date, binary — which in a schemaless database is half the information.

To edit, press the pencil: the document opens as extended JSON and is saved whole, identified by its _id. Without an _id it cannot be edited or deleted, and that is said instead of offering buttons that would touch a different document. Views are read-only and marked as such; capped collections are flagged too.

The menu at the top switches database, and Filter narrows the list of collections by name. Documents arrive in batches of 50: the footer counts those in the collection and those loaded, and Load more, at the end of the list, fetches the next batch. New document opens the same editor, empty; Format re-indents what is written and, if it cannot be read, says why without touching the text.

Calíope connects to MongoDB 4.0 or later. With an older version the connection is refused, saying which version the server is running.

With an environment label
If the profile’s label is read-only, the browser doesn’t offer New document, editing or deleting documents: you can only read. If it confirms writes, saving a document asks first with the label in front, and deleting one, which already asked, names the label in its question and doesn’t ask twice.

Keywords: mongodb, collections, documents, bson, json, browse

Query and aggregate

Filters, projections, sorting and aggregation pipelines.

Where it is: Workspace › Tools › Query

The query tool has two modes. “Find” applies a filter, a projection and a sort order, all three written as JSON documents. “Aggregate” runs a full pipeline, which is a list of stages.

The “Collection” menu picks what to query, from the database chosen in “Collections”, and “Run” (⌘↩) sends it. The footer counts the documents loaded and the milliseconds the server took. The fields take extended JSON, so {"$date": …} and {"$oid": …} reach the server as a date and an ObjectId, not as text. A pipeline that is not a list is caught before anything is sent; anything else the server rejects comes back with its own message.

Results arrive in pages: ask for more with “Load more”, and the server-side cursor is closed when the query changes or when you leave the tool — an abandoned one stays alive for ten minutes holding memory.

Results are not edited here: an aggregation has no original document to write changes back to, and with a projection the missing fields would be lost on save. Use the browser to edit.

The operators written in the filter and the pipeline have entries: the topic Contextual help for SQL functions explains it.

With an environment label
Find only reads and doesn’t change with the label. An aggregation with $out or $merge writes a collection: if the label is read-only it doesn’t run and the notice says why, and if it confirms writes, it asks first with the label in front.

Keywords: mongodb, query, find, aggregation, pipeline, filter

A collection’s indexes

View, create and drop indexes, including unique, sparse and expiring ones.

Where it is: Workspace › Tools › Indexes

Pick a collection in the Collection menu of the bar; views are not listed, because a view has no indexes of its own; if the collection chosen in another MongoDB tool is a view, the tool says so instead of reading it. The list shows each index by name, with its keys underneath and its properties as tags: unique, sparse or with an expiry (TTL). A text index shows the fields it covers, each one with “text”. Refresh reads the list again from the server.

New index opens a sheet with a Name, the Keys written as a document (1 is ascending, -1 descending, and “text” or “2dsphere” are valid for text and geospatial indexes) and three switches: unique, sparse and Expiry (TTL). With an expiry, Seconds is how long a document lives after the date in the indexed field, and it has to be a whole number: otherwise Create stays off. Create sends it to the server; if the server refuses it, for example because a unique index finds repeated values, its message appears in the sheet, which stays open.

The _id index cannot be dropped because the server maintains it, so no button is offered. Any other one is dropped with its bin, after a confirmation, and the queries that used it will scan the whole collection.

With an environment label
If the profile’s label is read-only, New index and each index’s trash button aren’t offered: the list is still read. If it confirms writes, creating an index asks first with the label in front, and deleting one, which already asked, names the label in its question and doesn’t ask twice.

Keywords: mongodb, indexes, unique, ttl, text, 2dsphere

Server status, operations and users

What on the relational side are the dashboard, the process list and users.

Where it is: Workspace › Tools › Server

It gathers three things that in MongoDB come from three server commands, one per section of the segmented control: Server (host, version, uptime, connections, memory and cumulative operations), Operations (what the server is doing right now) and Users (the users with their roles). Nothing refreshes on its own: each section is read when you open it, and Refresh reads it again.

In Operations, each row shows the kind of operation, its namespace, how many seconds it has been running and the connection it comes from. Include idle adds the connections that are open and doing nothing, and the server’s threads that are resting. Stop operation asks the server to end one, and it is offered only for operations that come from a client: the server’s own threads, such as Checkpointer, have no button, because it would not stop them.

Users lists every user on the server, from every database, as user@database: a user lives in a database. A role from another database carries its own @. Custom roles belong to a specific database, so the ones listed are those of the database chosen in the other tabs, and the section title names it.

With an environment label
If the profile’s label is read-only, no operation offers Stop operation: the three sections are still read. If it confirms writes, stopping an operation asks first with the label in front.

Keywords: mongodb, server, operations, users, roles, currentop

See which operations were slow

The MongoDB profiler: what level each database is at and what it recorded.

Where it is: Workspace › Tools › Profiler

The profiler has three levels: off, only the operations that cross the threshold, and all of them. The threshold is in milliseconds —not in seconds, like MySQL’s— and the sample rate, between 0 and 1, says what proportion of the slow ones gets recorded: below 1 the server discards slow operations on purpose.

The level belongs to each database, not to the server. That is why the toolbar carries its database picker and everything read and written refers to the chosen one. And it lives in memory: restarting the server returns it to whatever its startup configuration says.

What gets recorded goes to “system.profile”, a 1 MB capped collection per database: it is a window on the latest operations, not a history, and its documents have no “_id”, so they are read and not edited. Emptying it drops the collection, and that requires turning the profiler off for a moment: Calíope turns it off, drops it and restores the level that was there.

Below the settings, the list shows what “system.profile” holds, newest first: time, operation, namespace, milliseconds and, when the server records them, the plan, the documents and keys examined, the documents returned and the client. Only the latest 200 are read, and the footer says so. A double click or Return on the Mac, or a tap on the row anywhere else, opens the whole recorded document; from there, and from the row’s menu, “Copy the JSON” copies it and “Copy and open Query” copies just its command and opens Query. “Auto-refresh (10 s)” reads everything again every ten seconds, “Read” says when it last did, and “Refresh” also reloads the list of databases.

“Level”, “Threshold” and “Sample rate” change nothing until “Apply”, and afterwards Calíope reads the profiler back: the server answers with the settings from before, not the new ones.

There is no “by statement” view like the one in the relational slow query log: MongoDB publishes no aggregate summary by operation shape, and computing it on the client over a 1 MB window would claim more than the data supports.

On shared Atlas and behind “mongos” levels 1 and 2 cannot be set: there the server only accepts 0.

With an environment label
If the profile’s label is read-only, Change this database’s profiler and Empty the profiler aren’t shown: the state and the recorded operations remain. If it confirms writes, applying asks first with the label in front, and emptying, which already asked, names the label in its question and doesn’t ask twice.

Keywords: mongodb, profiler, slow, slowms, system.profile, sample rate

Send commands to the server

The way out for whatever the interface does not cover.

Where it is: Workspace › Tools › Commands

In MongoDB a command is a document, and this tool sends it as-is and shows the whole response.

It covers what no interface does: validating a collection, asking for statistics, explaining a query or any administrative command. You type the document in the editor and press Run (⌘↩). The Examples menu brings the most frequent ones ready to run; those that act on a collection carry “COLLECTION” where its name goes.

The menu at the start of the toolbar chooses which database it goes to, because some commands are only accepted on “admin”: getCmdLineOpts, for instance, which shows the options the server was started with.

The response arrives as a tree, and the arrow next to a subdocument or an array opens it. If the text is not valid JSON, Calíope says where before sending anything; if the server rejects the command, the warning carries its code and its name. A write can also be accepted by halves: an insert that a validator rejects still answers ok: 1, and the rejected document comes inside writeErrors, with the rule it broke.

With an environment label
The tool is also offered on a read-only connection, because it’s useful for reading. Calíope keeps a list of the commands that read —find, aggregate without $out or $merge, count, distinct, listCollections, listIndexes, listDatabases, dbStats, collStats, serverStatus, buildInfo, hello, isMaster, ping, explain, getLog, currentOp, connectionStatus, hostInfo, getParameter, getCmdLineOpts, validate, usersInfo, rolesInfo, getMore and killCursors— and everything else counts as a write, including a command it doesn’t know. If the label is read-only, a command that writes isn’t sent and the response says why; if it confirms writes, it asks first with the label in front.

Keywords: mongodb, commands, runcommand, validate, explain, statistics

The chosen collection applies to every MongoDB tool

The database and collection you pick in Collections are the ones Query, Indexes and the other MongoDB tools of the session use.

Where it is: Workspace › Tools › Collections

The database and collection you pick in Collections belong to the session, not to the tab: Query, Indexes and the other MongoDB tools that work on a collection use the same ones, and they are kept when you switch tabs.

Changing the database in the menu leaves the collection unselected, so nothing reads from a collection of another database. When the session opens, the profile’s database is preselected or, if it has none, the first one that is not admin, config or local.

Keywords: collection, database, MongoDB, session, tools

MongoDB reports: collection, find and aggregate

In a MongoDB session a report picks its collection and its shape —a filter with find or a pipeline with aggregate—, both in Extended JSON.

Where it is: Workspace › Tools › Reports

In a MongoDB session, a new report starts as find (filter) with an empty collection. Above the text are Collection and Shape: the first says which collection is read, and the second chooses between find (filter) and aggregate (pipeline).

Both are written in Extended JSON. A pipeline has to be an array, and each stage an object; otherwise the report is rejected before it runs. Parameters are written "$$name". Changing the shape starts the text from scratch: {} for a filter and [] for a pipeline.

A MongoDB report has no Stop and no Schedule: it cannot be cancelled halfway, and only relational reports can be scheduled.

Keywords: report, MongoDB, collection, find, aggregate, pipeline, Extended JSON