retentio/boomgo
Boomgo is a MongoDB ODM for Laravel that brings Eloquent-style models to document databases. It offers schema definitions, relationships, query building, and seamless Laravel integration, making MongoDB feel familiar to Laravel developers.
Boomgo is a small, annotation-driven ODM: it maps plain PHP classes onto MongoDB collections, hydrates query results back into those classes, and gets out of your way. Treat it as a mapper, not a full persistence framework — there is no unit of work, no schema tooling, and no lazy-loading proxies to reason about.
Minimal path to first document:
composer require retentio/boomgo and confirm your driver situation (see Gotchas — this library predates the mongodb extension and was written against the legacy mongo driver).insert, find, findOne, and update as you would with the raw driver — you get objects back instead of arrays.First realistic use case: a read-mostly feature (activity feed, catalog, CMS content) where you already know the document shape and just want typed objects in and out without dragging in Doctrine ODM. Start by modelling two or three related classes — one root document plus one embedded value object — and run a full insert/find/update round-trip against a scratch database before writing any application code.
Where to look first in the repo: the mapper/hydrator class (how annotations are parsed and how values are cast), then the collection/document-manager class (what query methods are actually proxied through). Those two files are the whole mental model of the package.
Root document + embedded value objects. The strongest fit for this library. Model an Address, Money, or LineItem as an embedded class and nest it inside the root document. You get object graphs on read without joins, and atomic single-document writes. Prefer embedding aggressively; reach for references only when the child is large, shared, or independently queried.
References for genuinely shared entities. When you must link across collections, store a reference and resolve it explicitly in the owning repository rather than relying on implicit traversal. Batch the resolution (collect all ids from the result set, issue one $in query, stitch in PHP) — naive per-document resolution is the fastest way to turn a 20-document page into 21 round trips.
Repository-per-aggregate. Even though Boomgo hands you a generic collection, wrap it. Create a small repository class that owns the query building for one document type (findActiveByOwner(), recentlyUpdated()), and inject the Boomgo collection into it. This is the single highest-leverage pattern with a lightweight ODM: it gives you a seam for testing, a place to centralise index assumptions, and keeps driver-specific query arrays out of controllers and services.
Bootstrap once, inject everywhere. Construct the manager during application bootstrap from config (not env vars read deep inside a model), register it as a shared service, and pass repositories into your services. Avoid static access to the manager — it makes tests need a live database and hides the dependency.
Explicit writes. Expect to call insert/update/save yourself; assume there is no dirty-tracking. Read-modify-write on a hydrated object then persisting the whole document is fine for small documents and much simpler than field-level $set; switch to targeted updates only where concurrent writers can clobber each other.
Schema evolution by convention. Mongo is schemaless, so give every document class a constructor that fills defaults for fields that may be absent on older documents. Hydration of a pre-existing document missing a property is the most common source of runtime fatals in this style of ODM. For structural changes, write a one-off backfill script with the raw driver, not through the ODM.
Testing. Point the manager at a *_test database, drop the collections in setUp, seed with fixtures, and assert on hydrated objects. Because repositories are injected, you can also fake them for service-level unit tests and reserve the real database for a thinner integration layer.
mongo extension, which was removed in PHP 7. Before committing, confirm whether the fork you're pulling targets mongodb + mongodb/mongodb or still calls MongoClient/MongoCollection. If it's the latter, you are either pinning an ancient PHP runtime, patching the connection layer, or choosing a different ODM. This one check decides the whole evaluation.findOne calls for the same id yield two distinct objects; mutating one does not affect the other, and neither is persisted until you say so. Design services around "load, mutate, save" and don't assume object identity.nulls or type juggling. Add defensive defaults in constructors and cast explicitly._id comes back as an ObjectId object unless the mapper converts it. This bites in JSON responses, route-model binding, and array key lookups. Normalise at the repository boundary — one place, consistently.DateTime in the default timezone. Store UTC, convert at the presentation edge, and be suspicious of any DateTime you reconstruct for query ranges.explain() on your hot queries.version field, use a conditional update ({_id: ..., version: n} plus $inc), and retry on a zero-match result.mongosh — mapping bugs and query bugs look identical from PHP. db.setProfilingLevel(2) on a dev database saves more time than any amount of var_dump.__wakeup/setter hooks if the mapper supports them (value casting), and subclassing the manager to override connection setup. Keep those overrides in one place in your app so the library stays replaceable.mongodb/mongodb library — or Doctrine ODM — is a contained change rather than an application-wide rewrite.How can I help you explore Laravel packages today?