{"id":16889051,"url":"https://github.com/algesten/mung","last_synced_at":"2025-07-24T20:08:07.882Z","repository":{"id":54143847,"uuid":"240878162","full_name":"algesten/mung","owner":"algesten","description":"mongodb tool with less suck","archived":false,"fork":false,"pushed_at":"2021-03-08T06:36:42.000Z","size":128,"stargazers_count":3,"open_issues_count":8,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-10T23:51:15.705Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/algesten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-16T11:18:25.000Z","updated_at":"2020-09-24T08:02:54.000Z","dependencies_parsed_at":"2022-08-13T07:31:07.765Z","dependency_job_id":null,"html_url":"https://github.com/algesten/mung","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fmung","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fmung/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fmung/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fmung/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/algesten","download_url":"https://codeload.github.com/algesten/mung/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247335702,"owners_count":20922489,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T16:55:24.138Z","updated_at":"2025-04-05T12:26:51.618Z","avatar_url":"https://github.com/algesten.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"mung\n====\n\n\u003e mongodb tool with less suck.\n\n[MongoDB](https://www.mongodb.com) is an acquired taste. One of it's\nbigger shortcomings is the lack of reasonable tooling for handling the\ndata. The mongo shell doesn't make a distinction between stdout/stderr\nand is very difficult to use as part of CLI scripts, piping, etc.\n\n[`jq`](https://stedolan.github.io/jq/) has become a defacto standard\nfor wrangling JSON from the command line. The intention is that `mung`\nworks well in tandem with `jq` to query and manipulate data in\nMongoDB.\n\n## Scope\n\n`mung` focuses on a narrow subset of everything that can be done in\nmongo shell. The aim is querying and data manipulation. Topics such as\nmanaging databases, index and clusters are (for now), out of scope.\n\n`mung` is opinionated about keeping the syntax simple. MongoDB full\nsyntax is extremely complex and often have overlapping ways of\nachieving similar things.\n\nMung is written in Rust and relies on the [official MongoDB Rust\ndriver](https://crates.io/crates/mongodb) which is currently in alpha\n(BE WARNED!).\n\n### Commands implemented\n\n  * [`find`](#find)\n  * [`count`](#count)\n  * [`distinct`](#distinct)\n  * [`insert`](#insert)\n  * [`update`](#update)\n  * [`remove`](#remove)\n\n# Install\n\nYou need rust 1.39+ installed. https://rustup.rs\n\n```bash\n$ cargo install --git ssh://git@github.com/algesten/mung\n```\n\n# Help\n\n`mung -h` shows usage help.\n\n```\nmung 0.1.0\nmongodb tool with less suck\n\nUSAGE:\n    mung [FLAGS] [OPTIONS] \u003cCOMMAND\u003e\n\nFLAGS:\n    -c, --compact     Compact instead of pretty printed output\n    -h, --help        Prints help information\n    -W, --password    Prompt for password\n    -V, --version     Prints version information\n    -v, --verbose     Verbose mode (-v, -vv, -vvv, etc.)\n\nOPTIONS:\n    -d, --dbname \u003cdbname\u003e    Database to use [env: MONGO_DB=]  [default: test]\n    -u, --url \u003curl\u003e          URL to connect to [env: MONGO_URL]  [default: mongodb://127.0.0.1:27017]\n\nARGS:\n    \u003cCOMMAND\u003e    Command to run or \"-\" to read from stdin\n```\n\n# Connect to a DB\n\n`mung` uses the URL form for connecting to MongoDB. The argument is either passed\non the command line using `-u`, or read from the environment variable `MONGO_URL`.\n\nThe following forms are accepted:\n\n  * `mongodb://user:pass@myhost`\n  * `mongodb+srv://user:pass@mycluster`\n\nThe password can be read from stdin by using the `-W` option.\n\nThe rust mongodb driver accepts many [query\nparameters](https://docs.rs/mongodb/0.9.1/mongodb/options/struct.ClientOptions.html#method.parse)\nto modify the connection behavior\n\n```bash\n$ export MONGO_URL=\"mongodb+srv://dbUser:dbUserPassword@clusterx-abc123.mongodb.net\"\n$ mung -d production 'db.users.find({ username: \"martin\" })'\n```\n\n```bash\n$ mung -u \"mongodb+srv://dbUser:dbUserPassword@clusterx-abc123.mongodb.net\" \\\n       -d production 'db.users.find({ username: \"martin\" })'\n```\n\n## Select database\n\nThe default database is `test`, and is changed using the `-d`\nparameter. `mung` differs from mongo shell in that it ignores any\ndatabase passed in the URL. The command line argument is _always_ used\n(or defaulting to `test` if not present).\n\n# Commands\n\nThe commands tries to be as close to mongo shell as possible.\n\nAll commands have the form:\n\n`db.\u003ccollection\u003e.\u003ccommand\u003e([doc], ...)`\n\nThey all start with `db.` (which is the database pointed out by the\n`-d` parameter. Db is followed by the `collection` name to make\noperations on and then the `command` to run.\n\nCommands are either read from the command line, or from stdin using\n`-`. These are equivalent:\n\n  * `mung -d prod 'db.user.find()'`\n  * `echo 'db.user.find()' | mung -d prod -`\n\nAll content is expected to be utf-8.\n\n## Streaming\n\nMultiple commands are separated by whitespace, parsed and executed one\nby one in a streaming fashion. That means we can construct pipes that\nare not doing any unecessary buffering for combined operations like:\n\n```bash\n$ mung -d test \"db.users.find().limit(3)\" \\\n    | jq -r ._id \\\n    | xargs -I % echo 'db.users.remove({ _id: \"%\" })' \\\n    | mung -d test -\n```\n\nThis is an example to illustrate a feature and not the best way to do\nthis. Let's break that down.\n\n  1. `mung -d test \"db.users.find().limit(3)\"` find three users and\n     output the entire json to stdout.\n  2. `jq -r ._id` of the json, just pick the `_id` field.\n  3. `xargs -I % echo 'db.users.remove({ _id: \"%\" })'` Row-by-row\n     construct a new command to stdout.\n  4. `mung -d test -`. One by one, read the commands from stdin and \n     execute them.\n\n## Shell escaping\n\nMongo's query language makes extensive use of `$` Depending on shell,\nthis might clash with variable syntax. For bash this works:\n\n  * `mung -d prod 'db.user.find({ age: { $gt: 42 } })'` (single quote)\n  * `mung -d prod \"db.user.find({ age: { \\$gt: 42 } })\"` (double quote\n    and `\\$`)\n\n# find\n\n`db.collection.find(\u003cquery\u003e, \u003cprojection\u003e)`\n\nQueries for documents. See [mongo\ndoc](https://docs.mongodb.com/manual/reference/method/db.collection.find/)\nfor how to construct queries.\n\nBoth `query` and `projection` are optional. Without any arguments, all\ndocuments are returned.\n\n## JSONL not Array\n\nThe output from `find()` is streaming, which means each JSON doc is\nprinted straight to stdout. When `find()` returns multiple documents,\neach doc is printed after another without being wrapped in an\narray or separated by commas.\n\n```json\n{\"doc\": 1}\n{\"doc\": 2}\n```\n\nThe default is not strict JSONL, because all output is pretty printed\nwhich means newline does not mean a new value. By using the `-c`\n(compact) option, we get JSONL. It is the same behavior as `jq`.\n\n```bash\n$ mung -d prod -c 'db.users.find({}, {_id: 1})'\n{\"_id\": \"user1\"}\n{\"_id\": \"user2\"}\n...\n```\n\nIf you want an array, use `jq`'s \"slurp\" feature:\n\n```bash\n$ mung -d prod 'db.users.find({}, {_id: 1})' | jq '._id' | jq -s\n[\n  \"user1\",\n  \"user2\",\n  ...\n]\n```\n\n### Examples\n\n  * `mung -d prod 'db.users.find()'`\n  * `mung -d prod 'db.users.find({ age: { $gt: 42 } })'`\n  * `mung -d prod 'db.users.find({ age: { $gt: 42 } }, { name: 1 })'`\n\n## Sorting\n\nSorting is added as a tail to the find command and works like in\n[mongo\nshell](https://docs.mongodb.com/manual/reference/method/cursor.sort/).\n\n`db.collection.find(...).sort(\u003csort\u003e)`\n\nExample\n\n  * `mung -d prod 'db.users.find().sort({ age: -1 }'`\n\n## `limit`, `skip` and `batchSize`\n\nThese options are added to the tail and works like in mongo shell.\n\n * `db.collection.find().limit(3)` (return 3 results). [See mongo\n   doc](https://docs.mongodb.com/manual/reference/method/cursor.limit/)\n * `db.collection.find().skip(3)` (skip first 3 results). [See mongo\n   doc](https://docs.mongodb.com/manual/reference/method/cursor.skip/)\n * `db.collection.find().batchSize(1000)` (load 1000 results at a time). [See mongo\n   doc](https://docs.mongodb.com/manual/reference/method/cursor.batchSize/)\n\n# count\n\n`db.collection.count(\u003cquery\u003e)`\n\nCounts number of matching documents like [mongo\nshell](https://docs.mongodb.com/manual/reference/method/db.collection.count/).\n\n### Examples\n\n  * `mung -d prod 'db.users.count()'`\n  * `mung -d prod 'db.users.count({ age: { $gt: 42 } })'`\n\n# distinct\n\n`db.collection.distinct([field], \u003cquery\u003e)`\n\nCounts number of distinctly different values of `field` in\n`collection. Optionally provides a `query` filter. [See mongo\ndocs](https://docs.mongodb.com/manual/reference/method/db.collection.distinct/).\n\n### Examples\n\n  * `mung -d prod 'db.users.distinct('age')'` (How many different age\n    values users)\n  * `mung -d prod 'db.users.distinct('age', { age: { $gt: 42 } })'`\n    (How many different age values of users over 42)\n\n# insert\n\n`db.collection.insert([doc or array])`\n\nInserts one or many docs into collection. See [mongo\ndoc](https://docs.mongodb.com/manual/reference/method/db.collection.insert/).\n\n### Examples\n\n  * `mung -d prod 'db.users.insert({ name: \"martin\", age: 34 })'`\n  * `mung -d prod 'db.users.insert([ { name: \"martin\", age: 34 }, { name: \"G\", age: 34 } ])'`\n\n# update\n\n`db.collection.update([query], [update], \u003copts\u003e)`\n\nUpdates one (or many with `opts.multi`) document. The `query` document\nis what to match, and `update` is the update to run. See [mongo\ndoc](https://docs.mongodb.com/manual/reference/method/db.collection.update/)\nfor details.\n\nBy default, even if the query matches many documents, only one single\ndocument is updated unless we pass `opts.multi`.\n\n## Options\n\n  * `multi` to update more than one doc.\n  * `upsert` to fall back to an insert if the query didn't match\n    anything. See [mongo\n    doc](https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-upsert)\n\n### Examples:\n\n  * `mung -d prod 'db.users.update({ _id: 'abcdef123' }, { $set: {\n    age: 43 } })'`. Update user with specific id and set `age` field\n    to `43`.\n  * `mung -d prod 'db.users.update({ age: { $gt: 42 } }, { $set: {\n    cool: true } }, { multi: true })'`. Update all (multi) users over\n    42 and set a field `cool` to `true`.\n\n# remove\n\n`db.collection.remove([query])`\n\nRemoves one or many documents matching the query. Pass `{}` to remove\neverything in the collection.\n\n### Examples:\n\n  * `mung -d prod 'db.users.remove({ _id: 'abc123' })'`. Remove one\n    document with specific id.\n  * `mung -d prod 'db.users.remove({ name: \"martin\" })'`. Remove all\n    users named martin.\n  * `mung -d prod 'db.users.remove({})'`. Remove all users.\n\n# Logging\n\nUse `-v` to get more logging and `-vv` for max logging. Credentials\npart of the URL will leak with logging turned on.\n\nThe `-v` targets only `mung` itself. To turn on logging for all\ndependent libraries, use the `MUNG_LOG` environment variable\nset to something like `MUNG_LOG=trace`.\n\n# License\n\nCopyright (c) 2020 Martin Algesten\n\n- MIT license\n  ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falgesten%2Fmung","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falgesten%2Fmung","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falgesten%2Fmung/lists"}