{"id":13616797,"url":"https://github.com/dunglas/doctrine-json-odm","last_synced_at":"2026-02-06T13:20:38.102Z","repository":{"id":8211454,"uuid":"57223826","full_name":"dunglas/doctrine-json-odm","owner":"dunglas","description":"An object document mapper for Doctrine ORM using JSON types of modern RDBMS.","archived":false,"fork":false,"pushed_at":"2024-11-26T13:59:19.000Z","size":135,"stargazers_count":610,"open_issues_count":14,"forks_count":66,"subscribers_count":20,"default_branch":"main","last_synced_at":"2025-04-10T14:12:28.887Z","etag":null,"topics":["doctrine","json","mysql","normalizer","odm","postgresql","symfony","symfony-bundle"],"latest_commit_sha":null,"homepage":"https://dunglas.fr","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dunglas.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"dunglas"}},"created_at":"2016-04-27T15:19:44.000Z","updated_at":"2025-04-10T09:33:11.000Z","dependencies_parsed_at":"2022-09-16T00:10:55.723Z","dependency_job_id":"a890962e-e66b-488b-b650-98202bd8aa1a","html_url":"https://github.com/dunglas/doctrine-json-odm","commit_stats":{"total_commits":96,"total_committers":33,"mean_commits":2.909090909090909,"dds":0.5729166666666667,"last_synced_commit":"c76280318ffb60aecceaf7f178298727c3dc35a5"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fdoctrine-json-odm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fdoctrine-json-odm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fdoctrine-json-odm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fdoctrine-json-odm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dunglas","download_url":"https://codeload.github.com/dunglas/doctrine-json-odm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254044401,"owners_count":22005153,"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":["doctrine","json","mysql","normalizer","odm","postgresql","symfony","symfony-bundle"],"created_at":"2024-08-01T20:01:33.407Z","updated_at":"2026-02-06T13:20:38.086Z","avatar_url":"https://github.com/dunglas.png","language":"PHP","funding_links":["https://github.com/sponsors/dunglas"],"categories":["PHP"],"sub_categories":[],"readme":"# Doctrine JSON ODM\n\nAn Object-Document Mapper (ODM) for [Doctrine ORM](http://www.doctrine-project.org/projects/orm.html) leveraging new JSON types of modern RDBMS.\n\n[![tests](https://github.com/dunglas/doctrine-json-odm/actions/workflows/tests.yml/badge.svg)](https://github.com/dunglas/doctrine-json-odm/actions/workflows/tests.yml)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/dunglas/doctrine-json-odm/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/dunglas/doctrine-json-odm/?branch=master)\n[![StyleCI](https://styleci.io/repos/57223826/shield)](https://styleci.io/repos/57223826)\n\nDid you ever dream of a tool creating powerful data models mixing traditional, efficient relational mappings with modern\nschema-less and NoSQL-like ones?\n\nWith Doctrine JSON ODM, it's now possible to create and query such hybrid data models with ease. Thanks to [modern JSON\ntypes of RDBMS](http://www.postgresql.org/docs/current/static/datatype-json.html), querying schema-less documents is easy,\npowerful and [fast as hell (similar in performance to a MongoDB database)](http://www.enterprisedb.com/postgres-plus-edb-blog/marc-linster/postgres-outperforms-mongodb-and-ushers-new-developer-reality)!\nYou can even [define indexes](http://www.postgresql.org/docs/current/static/datatype-json.html#JSON-INDEXING) for those documents.\n\nDoctrine JSON ODM allows to store PHP objects as JSON documents in modern, dynamic columns of an RDBMS.\nIt works with JSON and JSONB columns of PostgreSQL (\u003e= 9.4) and the JSON column type of MySQL (\u003e= 5.7.8).\n\nFor more information about concepts behind Doctrine JSON ODM, take a look at [the presentation given by Benjamin Eberlei at Symfony Catalunya 2016](https://www.youtube.com/watch?v=E8w1y1Jo7YI).\n\n## Install\n\nTo install the library, use [Composer](https://getcomposer.org/), the PHP package manager:\n\n    composer require dunglas/doctrine-json-odm\n\nIf you are using [Symfony](https://symfony.com) or [API Platform](https://api-platform.com), you don't need to do anything else!\nIf you use Doctrine directly, use a bootstrap code similar to the following:\n\n```php\n\u003c?php\n\nrequire_once __DIR__.'/../vendor/autoload.php'; // Adjust to your path\n\nuse Doctrine\\DBAL\\Types\\JsonbType;\nuse Doctrine\\DBAL\\Types\\Type;\nuse Doctrine\\ORM\\EntityManager;\nuse Doctrine\\ORM\\Tools\\Setup;\nuse Dunglas\\DoctrineJsonOdm\\Serializer;\nuse Dunglas\\DoctrineJsonOdm\\Type\\JsonbDocumentType;\nuse Dunglas\\DoctrineJsonOdm\\Type\\JsonDocumentType;\nuse Symfony\\Component\\Serializer\\Encoder\\JsonEncoder;\nuse Symfony\\Component\\Serializer\\Normalizer\\ArrayDenormalizer;\nuse Symfony\\Component\\Serializer\\Normalizer\\BackedEnumNormalizer;\nuse Symfony\\Component\\Serializer\\Normalizer\\UidNormalizer;\nuse Symfony\\Component\\Serializer\\Normalizer\\DateTimeNormalizer;\nuse Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer;\n\n$serializer = new Serializer([new BackedEnumNormalizer(), new UidNormalizer(), new DateTimeNormalizer(), new ArrayDenormalizer(), new ObjectNormalizer()], [new JsonEncoder()]);\n\nif (!Type::hasType('json_document')) {\n    Type::addType('json_document', JsonDocumentType::class);\n    Type::getType('json_document')-\u003esetSerializer($serializer);\n}\n\n// jsonb_document requires Doctrine DBAL 4.3.0+\nif (class_exists(JsonbType::class) \u0026\u0026 !Type::hasType('jsonb_document')) {\n    Type::addType('jsonb_document', JsonbDocumentType::class);\n    Type::getType('jsonb_document')-\u003esetSerializer($serializer);\n}\n\n// Sample bootstrapping code here, adapt to fit your needs\n$isDevMode = true;\n$config = Setup::createAnnotationMetadataConfiguration([__DIR__ . '/../src'], $_ENV['DEBUG'] ?? false); // Adapt to your path\n\n$conn = [\n    'dbname' =\u003e $_ENV['DATABASE_NAME'],\n    'user' =\u003e $_ENV['DATABASE_USER'],\n    'password' =\u003e $_ENV['DATABASE_PASSWORD'],\n    'host' =\u003e $_ENV['DATABASE_HOST'],\n    'driver' =\u003e 'pdo_mysql' // or pdo_pgsql\n];\n\nreturn EntityManager::create($conn, $config);\n```\n\n## Usage\n\nDoctrine JSON ODM provides a `json_document` column type for properties of Doctrine entities.\nStarting with Doctrine DBAL 4.3.0+, a `jsonb_document` type is also available, leveraging native JSONB support.\n\nThe content of properties mapped with this type is serialized in JSON using the [Symfony Serializer](http://symfony.com/doc/current/components/serializer.html)\nthen, it is stored in a dynamic JSON column in the database.\n\nWhen the object will be hydrated, the JSON content of this column is transformed back to its original values, thanks again\nto the Symfony Serializer.\nAll PHP objects and structures will be preserved.\n\nYou can store any type of (serializable) PHP data structures in properties mapped using the `json_document` type.\n\nExample:\n\n```php\nnamespace App\\Entity;\n\nuse Doctrine\\ORM\\Mapping\\{Entity, Column, Id, GeneratedValue};\n\n// This is a typical Doctrine ORM entity.\n#[Entity]\nclass Foo\n{\n  #[Column]\n  #[Id]\n  #[GeneratedValue]\n  public int $id;\n\n  #[Column]\n  public string $name;\n\n  // Can contain anything: array, objects, nested objects...\n  #[Column(type: 'json_document', options: ['jsonb' =\u003e true])]\n  public $misc;\n\n  // Works with private and protected methods with getters and setters too.\n}\n```\n\n```php\nnamespace App\\Entity;\n\n// This is NOT an entity! It's a POPO (Plain Old PHP Object). It can contain anything.\nclass Bar\n{\n    public string $title;\n    public float $weight;\n}\n```\n\n```php\nnamespace App\\Entity;\n\n// This is NOT an entity. It's another POPO and it can contain anything.\nclass Baz\n{\n    public string $name;\n    public int $size;\n}\n```\n\nStore a graph of random object in the JSON type of the database:\n\n```php\n// $entityManager = $managerRegistry-\u003egetManagerForClass(Foo::class);\n\n$bar = new Bar();\n$bar-\u003etitle = 'Bar';\n$bar-\u003eweight = 12.3;\n\n$baz = new Baz();\n$baz-\u003ename = 'Baz';\n$baz-\u003esize = 7;\n\n$foo = new Foo();\n$foo-\u003ename = 'Foo';\n$foo-\u003emisc = [$bar, $baz];\n\n$entityManager-\u003epersist($foo);\n$entityManager-\u003eflush();\n```\n\nRetrieve the object graph back:\n\n```php\n$foo = $entityManager-\u003efind(Foo::class, $foo-\u003egetId());\nvar_dump($foo-\u003emisc); // Same as what we set earlier\n```\n\n### Using type aliases\n\nUsing custom type aliases as `#type` rather than FQCNs has a couple of benefits:\n- In case you move or rename your document classes, you can just update your type map without migrating database content\n- For applications that might store millions of records with JSON documents, this can also save some storage space\n\nYou can introduce type aliases at any point in time. Already persisted JSON documents with class names will still get deserialized correctly.\n\n#### Using Symfony\n\nIn order to use type aliases, add the bundle configuration, e.g. in `config/packages/doctrine_json_odm.yaml`:\n\n```yaml\ndunglas_doctrine_json_odm:\n    type_map:\n        foo: App\\Something\\Foo\n        bar: App\\SomethingElse\\Bar\n```\n\nWith this, `Foo` objects will be serialized as:\n\n```json\n{ \"#type\": \"foo\", \"someProperty\": \"someValue\" }\n```\n\nAnother option is to use your own custom type mapper implementing `Dunglas\\DoctrineJsonOdm\\TypeMapperInterface`. For this, just override the service definition:\n\n```yaml\nservices:\n    dunglas_doctrine_json_odm.type_mapper: '@App\\Something\\MyFancyTypeMapper'\n```\n\n#### Without Symfony\n\nWhen instantiating `Dunglas\\DoctrineJsonOdm\\Serializer`, you need to pass an extra argument that implements `Dunglas\\DoctrineJsonOdm\\TypeMapperInterface`.\n\nFor using the built-in type mapper:\n\n```php\n    // …\n    use Dunglas\\DoctrineJsonOdm\\Serializer;\n    use Dunglas\\DoctrineJsonOdm\\TypeMapper;\n    use App\\Something\\Foo;\n    use App\\SomethingElse\\Bar;\n    \n    // For using the built-in type mapper:\n    $typeMapper = new TypeMapper([\n        'foo' =\u003e Foo::class,\n        'bar' =\u003e Bar::class,\n    ]);\n    \n    // Or implement TypeMapperInterface with your own class:\n    $typeMapper = new MyTypeMapper();\n\n    // Then pass it into the Serializer constructor\n    Type::getType('json_document')-\u003esetSerializer(\n        new Serializer([new ArrayDenormalizer(), new ObjectNormalizer()], [new JsonEncoder()], $typeMapper)\n    );\n```\n\n### Limitations when updating nested properties\n\nDue to how Doctrine works, it will not detect changes to nested objects or properties.\nThe reason for this is that Doctrine compares objects by reference to optimize `UPDATE` queries.\nIf you experience problems where no `UPDATE` queries are executed, you might need to `clone` the object before you set it.\nThat way Doctrine will notice the change. See https://github.com/dunglas/doctrine-json-odm/issues/21 for more information.\n\n## FAQ\n\n**What DBMS are supported?**\n\nPostgreSQL 9.4+ and MySQL 5.7+ are supported.\n\n**Which versions of Doctrine are supported?**\n\nDoctrine ORM 2.6+ and DBAL 2.6+ are supported.\n\n**How to use [the JSONB type of PostgreSQL](http://www.postgresql.org/docs/current/static/datatype-json.html)?**\n\nWith Doctrine DBAL 4.3.0+, use the dedicated `jsonb_document` type:\n\n```php\n// ...\n\n    #[Column(type: 'jsonb_document')]\n    public $foo;\n\n// ...\n```\n\nFor older DBAL versions, set an option in the column mapping:\n\n```php\n// ...\n\n    #[Column(type: 'json_document', options: ['jsonb' =\u003e true])]\n    public $foo;\n\n// ...\n```\n\n**Does the ODM support nested objects and object graphs?**\n\nYes.\n\n**Can I use the native [PostgreSQL](http://www.postgresql.org/docs/current/static/datatype-json.html) and [MySQL](https://dev.mysql.com/doc/refman/en/json.html) /JSON functions?**\n\nYes! You can execute complex queries using [native queries](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/native-sql.html). \n\nAlternatively, install [scienta/doctrine-json-functions](https://github.com/ScientaNL/DoctrineJsonFunctions) to be able to use run JSON functions in DQL and query builders.\n\n**How to change the (de)serialization context**\n\nYou may need to change the (de)serialization context, for instance to avoid escaping slashes.\n\nIf you are using Symfony, modify your Kernel like this:\n\n```php\n\u003c?php\n// src/Kernel.php\n\ndeclare(strict_types=1);\n\nnamespace App;\n\nuse Doctrine\\DBAL\\Types\\Type;\nuse Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait;\nuse Symfony\\Component\\HttpKernel\\Kernel as BaseKernel;\nuse Symfony\\Component\\Serializer\\Encoder\\JsonEncode;\n\nclass Kernel extends BaseKernel\n{\n    use MicroKernelTrait;\n\n    public function boot(): void\n    {\n        parent::boot();\n\n        $type = Type::getType('json_document');\n        $type-\u003esetSerializationContext([JsonEncode::OPTIONS =\u003e JSON_UNESCAPED_SLASHES]);\n        $type-\u003esetDeserializationContext([/* ... */]);\n    }\n}\n```\n\n**How can I add additional normalizers?**\n\nThe Symfony Serializer is easily extensible. This bundle registers and uses a service with ID `dunglas_doctrine_json_odm.serializer` as the serializer for the JSON type.\nThis means we can easily override it in our `services.yaml` to use additional normalizers.\nAs an example we inject a custom normalizer service. Be aware that the order of the normalizers might be relevant depending on the normalizers you use.\n\n```yaml\n    # Add DateTime Normalizer to Dunglas' Doctrine JSON ODM Bundle\n    dunglas_doctrine_json_odm.serializer:\n        class: Dunglas\\DoctrineJsonOdm\\Serializer\n        arguments:\n          - ['@App\\MyCustom\\Normalizer', '@?dunglas_doctrine_json_odm.normalizer.backed_enum', '@?dunglas_doctrine_json_odm.normalizer.uid', '@dunglas_doctrine_json_odm.normalizer.datetime', '@dunglas_doctrine_json_odm.normalizer.array', '@dunglas_doctrine_json_odm.normalizer.object']\n          - ['@serializer.encoder.json']\n          - '@?dunglas_doctrine_json_odm.type_mapper'\n        public: true\n        autowire: false\n        autoconfigure: false\n```\n\n**When the namespace of a used entity changes**\n\nFor classes without [type aliases](#using-type-aliases), because we store the `#type` along with the data in the database, you have to migrate the already existing data in your database to reflect the new namespace.\n\nExample: If we have a project that we migrate from `AppBundle` to `App`, we have the namespace `AppBundle/Entity/Bar` in our database which has to become `App/Entity/Bar` instead.\n\nWhen you use `MySQL`, you can use this query to migrate the data:\n```sql\nUPDATE Baz\nSET misc = JSON_REPLACE(misc, '$.\"#type\"', 'App\\\\\\Entity\\\\\\Bar')\nWHERE 'AppBundle\\\\\\Entity\\\\\\Bar' = JSON_EXTRACT(misc, '$.\"#type\"');\n```\n\n## Credits\n\nThis bundle is brought to you by [Kévin Dunglas](https://dunglas.dev) and [awesome contributors](https://github.com/dunglas/doctrine-json-odm/graphs/contributors).\nSponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).\n\n## Former Maintainers\n\n[Yanick Witschi](https://github.com/Toflar) helped maintain this bundle, thanks!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunglas%2Fdoctrine-json-odm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdunglas%2Fdoctrine-json-odm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunglas%2Fdoctrine-json-odm/lists"}