2025-09-28
1. MongoDB Data Structure Design
For your requirements, a two-collection approach in MongoDB is clean, scalable, and highly effective. This separates the concept of the “master document” from its immutable historical versions.documentscollection: Stores the master record for each document. It always points to the latest version, acting as the main entry point.documentVersionscollection: Stores the immutable, chronological records of each version.
documents Collection Schema
This collection holds one document per callCode. The _id of this document is the unifying callCode. This makes lookups for a specific document very fast.
_id: (string) The unique, human-readablecallCodefor the document. Using this as the_idensures uniqueness and provides a direct lookup key.title: (string) The current title of the document. This can be updated here when a new version is created.latestRevisionNumber: (integer) Caching the latest revision number allows you to quickly know the current version count without querying the other collection.latestVersionId: (ObjectId) A direct reference to the_idof the corresponding document in thedocumentVersionscollection. This creates a fast link to the most recent version’s full details.createdAt: Timestamp of the very first version (revision 0).updatedAt: Timestamp of the most recent version.
documentVersions Collection Schema
This is the core of your version log. Every time a document is saved, a new, immutable document is created in this collection.
_id: (ObjectId) A unique identifier for this specific version record.documentId: (string) The unifyingcallCode. This is the most important field for grouping versions. You must create an index on this field.revisionNumber: (integer) The 0-indexed version number. A compound index on(documentId, revisionNumber)would be highly beneficial for performance.changelog: (string) A user-provided message describing the changes in this version.author: (object) Details of the user who created this specific version.storage: (object) An object containing all information needed to retrieve the immutable file from your archival repository (e.g., S3, local filesystem). Including a file hash is crucial for data integrity checks.createdAt: The timestamp when this specific version was created.
How This Design Meets Your Requirements:
- View Chronological Change History: This is a simple and efficient query.
- View a Specific Version Independently: Each version has its own document and a direct path to its immutable file.
- Get the Latest Version:
You can either use the
documentscollection for a very fast lookup or query thedocumentVersionscollection.
2. Exploration with a Graph Database (Neo4j)
A graph database excels at modeling and querying relationships. For version control, this is a very natural fit, creating a “chain” of revisions.Graph Model
We’ll define Nodes (the entities) and Relationships (how they connect). Nodes::Document: The conceptual document.- Properties:
callCode(unique identifier),title. :Version: An immutable version of a document.- Properties:
revisionNumber,changelog,createdAt,storagePath,hash, etc. :User: The user who created the version.- Properties:
userId,name.
HAS_VERSION: Connects a:Documentto all its:Versionnodes.PREVIOUS_VERSION: Connects a version to the one that came before it. This forms the chronological linked list.CREATED: Connects a:Userto the:Versionthey created.LATEST_VERSION: A special relationship from a:Documentto its most current:Versionfor fast access.
How This Model Meets Your Requirements:
1. View Chronological Change History: You can traverse thePREVIOUS_VERSION chain backwards from the latest version. This is extremely efficient in a graph database.
Cypher Query:
Comparison and Recommendation
| Feature | MongoDB (Document Model) | Neo4j (Graph Model) |
|---|---|---|
| Simplicity | Winner. The two-collection model is intuitive, easy to implement in Laravel, and maps well to application logic. | Higher learning curve for Cypher and graph concepts. Laravel integration is less common. |
| Performance | Excellent for the required queries (get history, get specific). Performance relies on proper indexing (documentId). | Excellent, especially for traversing the version chain. Can outperform MongoDB on complex relationship queries. |
| Flexibility | Very flexible. Adding new metadata to versions is trivial. | Very flexible. The schema-less nature allows for easy evolution. |
| Querying | Simple queries are very straightforward. Complex relationship queries (e.g., “find all documents revised by people in the same department”) require application-side logic or aggregation pipelines. | Winner. Excels at answering questions about relationships. “Who approved a version that was later reverted?” is a natural graph query. |
| Future-Proofing | Solid for most DMS needs. | Winner for complex scenarios. If you ever plan to add features like branching and merging documents, a graph model is vastly superior and almost purpose-built for it. |
Conclusion and Recommendation for Your Stack
For your current requirements and your Laravel/PHP stack, the MongoDB two-collection approach is the most pragmatic and recommended solution.- It’s a robust, scalable, and well-understood pattern.
- Integration with Laravel is seamless with mature packages like
jenssegers/mongodb. - It perfectly satisfies all your stated needs with simple, performant queries.

