This page describes Calíope 1.5, the version I am building right now. 1.4 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.
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.
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 — 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.
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. 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. 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.
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.
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 iPad, 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.
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.