{"id":13564671,"url":"https://github.com/event-driven-io/Pongo","last_synced_at":"2025-04-03T21:31:19.766Z","repository":{"id":246872608,"uuid":"824455134","full_name":"event-driven-io/Pongo","owner":"event-driven-io","description":"Pongo - Mongo but on Postgres and with strong consistency benefits","archived":false,"fork":false,"pushed_at":"2025-03-29T18:26:11.000Z","size":1872,"stargazers_count":1263,"open_issues_count":21,"forks_count":33,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-03T12:57:10.974Z","etag":null,"topics":["mogodb","nodejs","postgresql","typescript"],"latest_commit_sha":null,"homepage":"https://event-driven-io.github.io/Pongo/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/event-driven-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["event-driven-io"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2024-07-05T07:08:55.000Z","updated_at":"2025-03-28T13:50:45.000Z","dependencies_parsed_at":"2024-08-07T10:57:37.888Z","dependency_job_id":"3aa0da4c-613a-40fc-bb53-2e8e73ac1c27","html_url":"https://github.com/event-driven-io/Pongo","commit_stats":{"total_commits":213,"total_committers":5,"mean_commits":42.6,"dds":"0.028169014084507005","last_synced_commit":"1a7e6f56454de6f25fa1e58aacf66b3044a434d0"},"previous_names":["event-driven-io/pongo"],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/event-driven-io%2FPongo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/event-driven-io%2FPongo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/event-driven-io%2FPongo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/event-driven-io%2FPongo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/event-driven-io","download_url":"https://codeload.github.com/event-driven-io/Pongo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247060631,"owners_count":20877157,"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":["mogodb","nodejs","postgresql","typescript"],"created_at":"2024-08-01T13:01:34.291Z","updated_at":"2025-04-03T21:31:19.754Z","avatar_url":"https://github.com/event-driven-io.png","language":"TypeScript","readme":"[![](https://dcbadge.vercel.app/api/server/fTpqUTMmVa?style=flat)](https://discord.gg/VzvxR5Rb38) [\u003cimg src=\"https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge\u0026logo=linkedin\u0026logoColor=white\" height=\"20px\" /\u003e](https://www.linkedin.com/in/oskardudycz/) [![Github Sponsors](https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026link=https://github.com/sponsors/oskardudycz/)](https://github.com/sponsors/oskardudycz/) [![blog](https://img.shields.io/badge/blog-event--driven.io-brightgreen)](https://event-driven.io/?utm_source=event_sourcing_nodejs) [![blog](https://img.shields.io/badge/%F0%9F%9A%80-Architecture%20Weekly-important)](https://www.architecture-weekly.com/?utm_source=event_sourcing_nodejs)\n\n![](./src/docs/public/social.png)\n\n# Pongo\n\nPongo - Mongo but on Postgres and with strong consistency benefits.\n\n## Getting Started\n\nInstall Pongo as an npm module and save it to your package.json:\n\n```bash\nnpm install @event-driven-io/pongo\n```\n\nRead also [introduction article on my blog](https://event-driven.io/en/introducting_pongo/?utm_source=pongo_github) for more context.\n\n## Example\n\nYou can use Pongo syntax with explicit typing about supported syntax:\n\n```ts\nimport { pongoClient, ObjectId } from \"@event-driven-io/pongo\";\n\ntype User = { name: string; age: number };\n\nconst connectionString =\n  \"postgresql://dbuser:secretpassword@database.server.com:3211/mydb\";\n\nconst pongo = pongoClient(connectionString);\nconst pongoDb = pongo.db();\n\nconst users = pongoDb.collection\u003cUser\u003e(\"users\");\nconst roger = { name: \"Roger\", age: 30 };\nconst anita = { name: \"Anita\", age: 25 };\nconst cruella = { _id: ObjectId(), name: \"Cruella\", age: 40 };\n\n// Inserting\nawait users.insertOne(roger);\nawait users.insertOne(cruella);\n\nconst { insertedId } = await users.insertOne(anita);\nconst anitaId = insertedId;\n\n// Updating\nawait users.updateOne({ _id: anitaId }, { $set: { age: 31 } });\n\n// Deleting\nawait users.deleteOne({ _id: cruella._id });\n\n// Finding by Id\nconst anitaFromDb = await users.findOne({ _id: anitaId });\n\n// Finding more\nconst usersFromDb = await users.find({ age: { $lt: 40 } });\n```\n\nOr use MongoDB compliant shim:\n\n```ts\nimport { MongoClient, ObjectId } from \"@event-driven-io/pongo/shim\";\n\ntype User = { name: string; age: number };\n\nconst connectionString =\n  \"postgresql://dbuser:secretpassword@database.server.com:3211/mydb\";\n\nconst pongoClient = new MongoClient(postgresConnectionString);\nconst pongoDb = pongoClient.db();\n\nconst users = pongoDb.collection\u003cUser\u003e(\"users\");\nconst roger = { name: \"Roger\", age: 30 };\nconst anita = { name: \"Anita\", age: 25 };\nconst cruella = { _id: ObjectId(), name: \"Cruella\", age: 40 };\n\n// Inserting\nawait users.insertOne(roger);\nawait users.insertOne(cruella);\n\nconst { insertedId } = await users.insertOne(anita);\nconst anitaId = insertedId;\n\n// Updating\nawait users.updateOne({ _id: anitaId }, { $set: { age: 31 } });\n\n// Deleting\nawait users.deleteOne({ _id: cruella._id });\n\n// Finding by Id\nconst anitaFromDb = await users.findOne({ _id: anitaId });\n\n// Finding more\nconst usersFromDb = await users.find({ age: { $lt: 40 } }).toArray();\n```\n\n## How does it work?\n\n**Pongo treats PostgreSQL as a Document Database benefiting from JSONB support.** Unlike the plain text storage of the traditional JSON type, JSONB stores JSON data in a binary format. This simple change brings significant advantages in terms of performance and storage efficiency.\n\nPongo uses the following table structure for storing collections:\n\n```sql\nCREATE TABLE IF NOT EXISTS \"YourCollectionName\" (\n    _id           TEXT           PRIMARY KEY,\n    data          JSONB          NOT NULL,\n    metadata      JSONB          NOT NULL     DEFAULT '{}',\n    _version      BIGINT         NOT NULL     DEFAULT 1,\n    _partition    TEXT           NOT NULL     DEFAULT 'png_global',\n    _archived     BOOLEAN        NOT NULL     DEFAULT FALSE,\n    _created      TIMESTAMPTZ    NOT NULL     DEFAULT now(),\n    _updated      TIMESTAMPTZ    NOT NULL     DEFAULT now()\n)\n```\n\n**Essentially Pongo takes MongoDB api and translates it to the native PostgreSQL queries.** It is a similar concept to [Marten](https://martendb.io/), [FerretDB](https://docs.ferretdb.io) and [AWS DocumentDB](https://aws.amazon.com/documentdb/).\n\n**E.g. the MongoDB update syntax:**\n\n```ts\nconst users = pongoDb.collection\u003cUser\u003e(\"users\");\n\nawait users.updateOne({ _id: someId }, { $push: { tags: \"character\" } });\n```\n\nwill be translated to:\n\n```sql\nUPDATE \"users\"\nSET data = jsonb_set(data, '{tags}', (COALESCE(data-\u003e'tags', '[]'::jsonb) || to_jsonb('character')))\nWHERE _id = '137ef052-e41c-428b-b606-1c8070a47eda';\n```\n\n**Or for query:**\n\n```ts\nconst result = await users\n  .find({ \"address.history\": { $elemMatch: { street: \"Elm St\" } } })\n  .toArray();\n```\n\nwill result in:\n\n```sql\nSELECT data\nFROM \"users\"\nWHERE jsonb_path_exists(\n  data,\n  '$.address.history[*] ? (@.street == \"Elm St\")'\n);\n```\n\n## Why Pongo?\n\nMongoDB is a decent database, yet it has issues around [ACID-complaince](https://jepsen.io/analyses/mongodb-4.2.6) and [licensing](https://www.percona.com/blog/is-mongodb-open-source), which can cause hardship for project scenarios and organisation policies.\n\n**Pongo brings the [PostgreSQL shape-shifting capabilities](https://www.amazingcto.com/postgres-for-everything/) to:**\n\n- benefit from **strong consistency** by using battle-tested and widely used PostgreSQL ACID-compliant database,\n- **easier integration** with other parts of your system using PostgreSQL,\n- **reuse your muscle memory from MongoDB** using compatible API. It will allow easier migration of existing projects,\n- **cut boilerplate** and easier nested data management than traditional relational tables,\n- operate **easier than crafting native PostgreSQL JSON queries**. They're powerful but not the most accessible,\n- get **performance boost** with [JSONB indexing capabilities](https://pganalyze.com/blog/gin-index#postgresql-jsonb-and-gin-indexes),\n- **benefit from PostgreSQL advanced capabilities** like [partitioning](https://www.postgresql.fastware.com/postgresql-insider-prt-ove), [logical replication](https://event-driven.io/en/push_based_outbox_pattern_with_postgres_logical_replication/) and [other PostgreSQL superpowers](https://event-driven.io/en/postgres_superpowers/)\n- **seamless integration with Cloud RDSes** and solutions like [Supabase](https://supabase.com/), [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres), [YugabyteDB](https://www.yugabyte.com/yugabytedb/), [CockroachDB](https://www.cockroachlabs.com/docs/stable/why-cockroachdb), .\n\nWatch also more in:\n\n[![](https://img.youtube.com/vi/p-6fpV_GDEs/0.jpg)](https://www.youtube.com/live/p-6fpV_GDEs)\n\n## Storage\n\n**The binary format of PostgreSQL JSONB means that data is pre-parsed, allowing faster read and write operations than text-based JSON.** You don't have to re-parse the data every time you query it, which saves processing time and improves overall performance. Additionally, JSONB supports advanced indexing options like GIN and GiST indexes, making searches within JSONB documents much quicker and more efficient.\n\nMoreover, JSONB retains the flexibility of storing semi-structured data while allowing you to use PostgreSQL's robust querying capabilities. You can perform complex queries, joins, and transactions with JSONB data, just as you can with regular relational data.\n\n**Contrary to common belief, JSON document data is structured.** JSON has structure, but it is not enforced for each document. We can easily extend the schema for our documents, even for specific ones, by adding new fields. We should also not fail if a field we expect to exist doesn't.\n\nThis flexibility, performance, and consistency combination makes PostgreSQL with JSONB a powerful tool. There are benchmarks showing that it can be even faster than MongoDB.\n\nCheck more in:\n\n- [JSON Types Documentation](https://www.postgresql.org/docs/current/datatype-json.html)\n- [JSON Functions and Operators](https://www.postgresql.org/docs/current/functions-json.html)\n- [PostgreSQL, JSONB and GIN Indexes by](https://pganalyze.com/blog/gin-index#postgresql-jsonb-and-gin-indexes)\n- [MongoDB vs PostgreSQL JSONB Benchmark](https://info.enterprisedb.com/rs/069-ALB-339/images/PostgreSQL_MongoDB_Benchmark-WhitepaperFinal.pdf)\n- [How to JSON in PostgreSQL](https://ftisiot.net/postgresqljson/main/)\n- [Just Use Postgres for Everything](https://www.amazingcto.com/postgres-for-everything/)\n\n## Is Pongo an ORM?\n\n**It's not.**\n\nIt's focused on effective handling of the document data specifics. Node.js ORMs have capabilities to handle JSONB, e.g. DrizzleORM has good support for that for basic operations.\n\n**Yet, they all have limited querying capabilities.** Usually for advanced ones you need to fallback to JSONPath or JSONB functions (so raw SQL). As you saw above, this syntax is not super pleasant to deal with. That's why Pongo aims to do it for you.\n\n## How is it different than [FerretDB](https://docs.ferretdb.io)?\n\n[FerretDB](https://docs.ferretdb.io) plugs into the native MongoDB protocol, which allows it to be used as MongoDB and connect to tools like Mongo UI, etc. Yet, it [requires running a proxy](https://docs.ferretdb.io/quickstart-guide/docker/).\n\n**Pongo operates on a different layer, translating the MongoDB API directly into SQL in the library code.** This can allow easier serverless integrations, such as sharing a connection pool with other PostgreSQL-based tools, etc. Of course, it won't allow using native tools based on the MongoDB network protocol.\n\nPongo's goal is not to replace Mongo but to reuse its muscle memory and bring the PostgreSQL capabilities and superpowers into the Node.js land.\n\n## Is it production ready?\n\nWhat's there is safe to use, but it's far from being 100% compliant with MongoDB. Pongo is a fresh project, so some stuff can be missing.\n\n## Support\n\n💖 If you'd like this project and want us to deliver more and faster, feel invited to **join** the group of our 👉 [Github Sponsors](https://github.com/sponsors/event-driven-io).\n\nBy doing so, you're helping to make our work on it sustainable and continuing our efforts so we can support your products.\n\n**🥉 [Bronze Sponsors](https://github.com/sponsors/event-driven-io)**\n\n- [productminds](https://github.com/pminds)\n- [Lightest Night](https://github.com/lightest-night)\n\n## Contribution\n\nPongo is a community project, so once you find something missing or not working, we encourage you to [send us a GH issue](https://github.com/event-driven-io/Pongo/issues/new) or [Pull Request](https://github.com/event-driven-io/Pongo/compare) extending the support or test coverage! Check also [Contributing guide](https://github.com/event-driven-io/Pongo/blob/main/CONTRIBUTING.md)\n\n**If you think something is missing or want to get some features faster, I'm happy to take sponsoring to prioritise it. Feel free to [contact me](mailto:oskar@event-driven.io) - we'll find a way to help you!**\n\n## Code of Conduct\n\nThis project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/) to clarify expected behavior in our community.\n","funding_links":["https://github.com/sponsors/event-driven-io","https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026link=https://github.com/sponsors/oskardudycz/","https://github.com/sponsors/oskardudycz/"],"categories":["TypeScript","\u003ca name=\"TypeScript\"\u003e\u003c/a\u003eTypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevent-driven-io%2FPongo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevent-driven-io%2FPongo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevent-driven-io%2FPongo/lists"}