Morphia Documentation

repository·master·Indexed 23 days ago

https://github.com/morphiaorg/morphia

Morphia is a Java-based Object-Document Mapper (ODM) for MongoDB that allows developers to map Java classes to MongoDB documents. The library includes features for defining database indexes via the @Index annotation, GridFS mapping using Traditional and Wrapper styles, and build-time code generation tools like the critter Maven Mojos (generate-models and generate-criteria) to reduce runtime reflection overhead.

Tokens
23.5K
Snippets
47
Records
132
Agent score
82%

What's inside Morphia

  1. Map Java classes to MongoDB documents

    master

    Morphia uses annotations to map Java classes to MongoDB collections.

    Requirements for Persistence:

    • Classes must be annotated with either @Entity or @ExternalEntity to be recognized by Morphia.
    • Top-level entities (those stored as primary documents) must have a field annotated with @Id to define the _id value.
    • Embedded types (used as properties within other entities) do not require an @Id field.

    Common Annotations:

    • @Entity("collection_name"): Marks a class as a top-level entity. If a string is provided, it specifies the collection name; otherwise, Morphia uses the camel-case class name.
    • @Id: Defines the primary key field (e.g., ObjectId, long).
    • @Indexes: Used to define indexes on the collection.
    • @Index: Defines a specific index and its fields.
    • @Property("custom_name"): Maps a Java field to a different field name in the MongoDB document.
    • @Reference: Indicates the field refers to another Morphia-mapped entity (stored as a DBRef). The referenced entity must be saved or have an ID assigned before referencing it.

    Example Mapping:

    @Entity("employees")
    @Indexes(
        @Index(value = "salary", fields = @Field("salary"))
    )
    class Employee {
        @Id
        private ObjectId id;
        private String name;
        @Reference
        private Employee manager;
        @Reference
        private List<Employee> directReports;
        @Property("wage")
        private Double salary;
    }
  2. Migrate Query API from Morphia 2.5 to 3.0

    master

    The Query interface has been modernized to favor a structured, filter-based approach.

    Key Changes:

    • Removed Methods: Legacy methods such as criteria(), field(), execute(), and find() (the version returning a cursor) have been removed.
    • New Approach: Use the filter(Filter filter) method to build queries.
    • Execution: Use iterator() or stream() to retrieve results from a query.
    • Find and Modify: The findAndDelete() and findAndModify() methods have been updated with new FindAndDeleteOptions and FindAndModifyOptions to provide more control.
  3. Note on Aggregation API evolution

    master
    The Aggregation API in Morphia has undergone experimentation. Users should be aware that updates in the 2.1.0 cycle may introduce a parallel, experimental API designed to improve usability, which may eventually replace the existing implementation.
  4. Merge partial entities using Datastore#merge()

    master

    The merge() method is designed for scenarios where you have a partial entity (like a DTO) and want to update only the fields defined in that type using $set operators.

    Handling missing or null fields

    By default, merge() only issues $set for the fields present in the DTO. This means if a field is removed from the DTO (e.g., a List becomes empty), the old data might persist in the database.

    To ensure the database reflects the exact state of the in-memory object, use InsertOneOptions.unsetMissing(true). When set to true, any property defined on the entity that is not being updated via $set will have an $unset operator applied, removing null properties and empty Lists from the document.

    Regardless of the unsetMissing setting, merge() performs a find() and returns the updated form of the entity from the database.

  5. Configure @Id for top-level entities

    master

    A top-level entity (one that is mapped directly to a collection) must have at least one field annotated with @Id.

    Warning: Entities annotated with @Entity that lack an @Id field cannot serve as top-level types. They cannot be saved directly or used as the basis for queries; they can only exist as fields within other top-level entities. The ID field is also required for Morphia to perform proper updates on existing documents.

    The type of the ID field can be any type supported by a MongoDB codec.

  6. Migrate Aggregation Framework from Morphia 2.5 to 3.0

    master

    The Aggregation API has undergone a major redesign. In Morphia 2.5, the API used an extensive fluent interface where each stage (e.g., addFields, group, sort) was a direct method on the Aggregation object.

    In Morphia 3.0, the API has shifted to a streamlined pipeline-based approach. Instead of calling individual stage methods, you primarily use the pipeline(Stage stage) method to build the pipeline. To execute the aggregation, use iterator() or toList() instead of the legacy execute() methods.

  7. Use method-based mapping for properties

    master

    As of version 2.2, you can define mapping via methods (getters/setters) instead of fields.

    Rules for method mapping:

    1. Getters: Must take no parameters. The property type is determined by the return type. The property name is derived by stripping the get or is prefix and lower-casing the first letter.
    2. Setters: Must take one parameter. The parameter type should match the getter's return type. Setters must return void.
    3. Boolean types: Getters often use the is prefix (e.g., isEnabled()).

    Constraints:

    • You cannot use both field-based and method-based mapping simultaneously in the same configuration; you must choose one scheme.
    • Annotations can be placed on either the getter or the setter, but applying the same annotation to both can lead to unpredictable behavior. It is recommended to annotate the getter.
  8. Update Datastore operations for Morphia 3.0

    master

    The dev.morphia.Datastore interface has been consolidated to improve type safety and align with modern MongoDB driver patterns.

    Major Changes:

    • Aggregation Creation: aggregate(String) is replaced by createAggregation(Class). For advanced usage, use aggregate(AggregationOptions) or aggregate(Class, AggregationOptions).
    • Query/Update Creation: Use createQuery(Class), createUpdateOperations(Class), and createAggregation(Class) instead of legacy string-based or implicit creation methods.
    • Removal of String-based operations: Many methods that accepted String for collection or query names have been removed in favor of Class<T> to ensure type safety.
    • New Options Support: Many methods like delete, find, insert, and replace now include overloads that accept specific options objects (e.g., DeleteOptions, FindOptions, InsertOneOptions, ReplaceOptions).
  9. Perform multiple operations in a single update

    master

    You can chain multiple UpdateOperations to perform several changes in one atomic command.

    Important Constraints:

    • Order matters: If you perform multiple operations on the same property, the result depends on the order of execution (e.g., .inc("stars", 50).inc("stars") vs .inc("stars").inc("stars", 50)).
    • No conflicts: You cannot apply conflicting operations to the same property in a single command (e.g., calling both .set("stars", 1) and .inc("stars", 50) will cause an error).
    // Set city to Ottawa AND increment stars by 1 in one command
    UpdateOperations ops = datastore
        .createUpdateOperations(Hotel.class)
        .set("city", "Ottawa")
        .inc("stars");
    datastore.update(updateQuery, ops);
  10. How aggregation pipelines and stages work

    master

    An aggregation pipeline is a series of stages that process data. Each stage performs an operation on the documents passed to it from the previous stage.

    For example, the group() stage (the Morphia equivalent of the MongoDB $group operator) allows you to group documents based on specific criteria. You can define a group ID (e.g., grouping by an author field) and create new fields in the resulting documents (e.g., an array of book titles belonging to that author).

  11. Use MongoDB driver Options instead of Morphia Options

    master

    Starting with the 2.0 release cycle, Morphia has moved away from its own internal Option classes to reduce maintenance and provide immediate access to new MongoDB driver features.

    Instead of using Morphia-wrapped options, you should use the driver's native options classes directly. Because the interfaces are designed to be similar, migration typically involves updating import statements and potentially minor method calls.