Overview
In this guide, you can learn how to create Hibernate ORM entities that represent MongoDB collections. Entities are Java classes that define the structure of your data. When using the Hibernate ORM extension, you can map each entity to a MongoDB collection and use these entities to interact with the collection's documents.
Tip
Entities Tutorial
To view a tutorial that shows how to model one-to-many relationships by using entities and the Hibernate ORM extension, see the Modeling Relationships With Hibernate ORM and MongoDB Foojay blog post.
MongoDB BSON Fields
MongoDB organizes and stores documents in a binary representation called BSON that allows for flexible data processing. This section describes the Hibernate ORM extension's support for BSON fields, which you can include in your entities.
Tip
To learn more about how MongoDB stores BSON data, see BSON Types in the MongoDB Server manual.
The following table describes supported BSON field types and their Hibernate ORM extension equivalents that you can use in your Hibernate ORM entities:
BSON Field Type | Extension Field Type | BSON Description |
|---|---|---|
|
| Represents a null value or absence of data. |
|
| Stores binary data with subtype 0. |
|
| Stores UTF-8 encoded string values. The |
|
| Stores 32-bit signed integers. |
|
| Stores 64-bit signed integers. |
|
| Stores floating-point values. |
|
| Stores |
|
| Stores 28-bit decimal values. |
|
| Stores unique 12-byte identifiers that MongoDB uses as primary keys. |
|
| Stores dates and times as milliseconds since the Unix epoch. |
|
| Stores embedded documents with field values mapped according to their respective
types. |
|
| Stores array values with elements mapped according to their respective types. Character arrays require setting the |
Note
@JdbcTypeCode Annotation Is Not Supported
The Hibernate ORM extension does not support the @org.hibernate.annotations.JdbcTypeCode annotation and throws an exception if you use this annotation to override a field's type mapping.
Unsupported Field Types
Hibernate ORM serializes any Java type that implements java.io.Serializable to binary data when it has no other mapping for that type. To prevent your data from being stored in this format, the Hibernate ORM extension rejects the following types and throws an exception when your application starts. This check applies to primary keys, ordinary fields, embeddable attributes, and collection elements.
The following table describes unsupported field types and their supported alternatives:
Category | Unsupported Types | Supported Alternative |
|---|---|---|
Date and Time |
| Use |
BSON Values |
| Use |
BSON Documents |
| Use an |
Define an Entity
To create an entity that represents a MongoDB collection, create a new Java file in your project's base package directory and add your entity class to the new file. In your entity class, specify the fields you want to store and the collection name.
The name element of the @jakarta.persistence.Table annotation represents your MongoDB collection name. You can also set the optional schema element to prefix the collection name, as described in the Schema Qualifiers section of this guide. Use the following syntax to define an entity:
public class <EntityName> { // Specify your primary key field here private <field type> <field name>; // Include additional fields here private <field type> <field name>; // Parameterized constructor public <EntityName>(<parameters>) { // Initialize fields here } // Default constructor public <EntityName>() { } // Getter and setter methods public <field type> get<FieldName>() { return <field name>; } public void set<FieldName>(<field type> <field name>) { this.<field name> = <field name>; } }
To use your entities, you can query them in your application files. To learn more about CRUD operations in the Hibernate ORM extension, see the Perform CRUD Operations guide.
Important
Primary Key Field Name Must Be _id
MongoDB requires the primary key field to map to the _id field. You can explicitly set the @Id field's column name by using a @Column annotation or an orm.xml override. If you set this name to anything other than _id, the Hibernate ORM extension throws a FeatureNotSupportedException at bootstrap. To resolve this error, remove the @Column annotation or set its name to _id.
This validation does not apply to legacy Hibernate Mapping (HBM) XML mappings. If you map your entity by using HBM XML, the Hibernate ORM extension silently renames the identifier column to _id instead of throwing an exception.
Schema Qualifiers
The @Table annotation accepts an optional schema element that prefixes your collection name. When you set both elements, the Hibernate ORM extension maps the entity to a collection named <schema name>.<collection name>.
A schema qualifier changes only the collection's name. A schema is not a separate MongoDB database. Every schema-qualified collection resides in the database that your SessionFactory instance connects to. Because these collections share one database, a transaction can span multiple schemas.
Use the following syntax to apply a schema qualifier:
public class <EntityName> { // Define your fields, constructors, and methods here }
Note
Schema Qualifier Limitations
The Hibernate ORM extension rejects the catalog element of the @Table annotation and the hibernate.default_catalog configuration property at bootstrap. If your application must access multiple MongoDB databases, create a separate SessionFactory instance for each database.
The Hibernate ORM extension rejects a dot (.) in a table name or a schema name at bootstrap. This restriction applies to primary, secondary, join, and collection table names, and to schema names set by either the schema attribute or the hibernate.default_schema configuration property.
Example
This sample Movie.java entity class defines a Movie entity that includes the following information:
@Entityannotation that marks the class as a Hibernate ORM entity@Tableannotation that maps the entity to themoviescollection from the Atlas sample datasets@Idand@ObjectIdGeneratorannotations that designate theidfield as the primary key and configure automaticObjectIdgenerationTip
Primary Key Values
This example specifies the
ObjectIdfield as the entity's primary key, but you can also setStringorintfields as the primary key by using the@Idannotation. To learn more, see Unsupported Field Types.Private fields that represent movie data
Default and parameterized constructors for entity instantiation
Getter and setter methods that provide access to the entity's fields
package org.example; import com.mongodb.hibernate.annotations.ObjectIdGenerator; import org.bson.types.ObjectId; import java.util.List; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; public class Movie { private ObjectId id; private String title; private String plot; private int year; private List<String> cast; private List<String> directors; public Movie(String title, String plot, int year, List<String> cast, List<String> directors) { this.title = title; this.plot = plot; this.year = year; this.cast = cast; this.directors = directors; } public Movie() { } public ObjectId getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getPlot() { return plot; } public void setPlot(String plot) { this.plot = plot; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public List<String> getCast() { return cast; } public void setCast(List<String> cast) { this.cast = cast; } public List<String> getDirectors() { return directors; } public void setDirectors(List<String> directors) { this.directors = directors; } }
Tip
To learn more about the fields used in the entity class definition, see the MongoDB BSON Fields section of this guide.
Sequence-Generated IDs
The Hibernate ORM extension can assign increasing numeric IDs to your entities automatically. Some numbers may be missing if a transaction is rolled back or if an application does not use all the IDs it reserved.
The Hibernate ORM extension supports sequence-generated IDs for the short, int, and long types, and for the boxed Short, Integer, and Long types.
Add Sequence-Generated IDs to Your Entity
You can use the @GeneratedValue and @SequenceGenerator annotations to add sequence-generated IDs to your entity. The following example reserves IDs in blocks of 50 from the movies_SEQ counter:
private Long id;
The annotations control how the Hibernate ORM extension creates the ID:
@GeneratedValuetells the Hibernate ORM extension to create the value of theidfield. Itsstrategyandgeneratorattributes define how the extension creates the ID:strategy:AUTOorSEQUENCE. WithAUTO, the Hibernate ORM extension uses a sequence, and you don't have to declare a@SequenceGenerator. WithSEQUENCE, the Hibernate ORM extension uses the sequence generator named by thegeneratorattribute.generator: The name of the@SequenceGeneratorto use. If you omit this attribute, the Hibernate ORM extension names the sequence after the entity's table, such asmovies_SEQfor themoviestable.
@SequenceGeneratordefines the sequence generator:name: The name that the@GeneratedValuegeneratorattribute references.sequenceName: The name of the counter document. If you omit it, the Hibernate ORM extension uses the generator'sname.initialValue: The value that the first generated ID starts from. Defaults to1.allocationSize: The number of IDs reserved in each block.
Where IDs Are Stored
The Hibernate ORM extension stores counter documents in a fixed collection named hibernate_sequences. Each sequence uses one counter document that has the following fields:
_idis the sequence name.next_valueis the counter value that the Hibernate ORM extension advances to produce the next IDs. It must match theinitialValueof the sequence generator, which defaults to1.incrementis the number of IDs reserved at one time. It must match the sequence generator'sallocationSizevalue. If it doesn't, theSessionFactoryfails to start.
The Hibernate ORM extension gets IDs in blocks. This reduces the number of times it must contact the database. Requests made at the same time each receive a different ID.
Important
Counter Document Requirements
Both next_value and increment must be 64-bit integers (BSON Int64). A counter document that is missing either field, or that stores a value as a 32-bit integer, cannot allocate IDs. If schema management is disabled, you must create a counter document for each sequence before your application can allocate IDs.
Enable Schema Management
Schema management is Hibernate ORM's way of creating the database objects that your entities need. The Hibernate ORM extension uses it to create the counter documents for sequence-generated IDs.
To enable schema management, set the jakarta.persistence.schema-generation.database.action property in your hibernate.properties or persistence.xml file. Use one of the following values:
create: Creates the counter documents and keeps them when theSessionFactorycloses.create-drop: Creates the counter documents when theSessionFactoryopens and drops them when it closes.
The following example uses create:
jakarta.persistence.schema-generation.database.action=create
Disable Schema Management and Manual Counter Setup
If you prefer to turn off schema management, you can manually create counter documents for sequence-generated IDs. Set the following property:
jakarta.persistence.schema-generation.database.action=none
Then create one counter document in the hibernate_sequences collection for each sequence. The _id of the counter document must match the sequenceName of the sequence generator.
The following example uses the MongoDB Java driver to insert the movies_SEQ counter document into the hibernate_sequences collection of the database that you indicate:
// Replace the placeholders with your connection string and database name. MongoClient client = MongoClients.create("<connection string>"); MongoDatabase database = client.getDatabase("<database name>"); database.getCollection("hibernate_sequences").insertOne( new Document("_id", "movies_SEQ") .append("next_value", new BsonInt64(1)) .append("increment", new BsonInt64(50)));
The insert creates the counter document shown. Set next_value to the generator's initialValue and increment to its allocationSize.
Save an Entity and Read Its Generated ID
The following example saves a new Movie entity and prints its generated ID. The ID depends on the starting point of the sequence. For a new counter that starts at 1, the output is:
var movie = new Movie(); movie.setTitle("The Matrix"); session.persist(movie); System.out.println("Movie created with ID: " + movie.getId());
Unsupported Configurations
The Hibernate ORM extension does not support the following sequence-related strategies, types, and configurations:
IDENTITYandTABLEgeneration strategiesBigIntegerandBigDecimalgenerated identifier typesSequence names or schemas that contain a
.characterSequence names qualified by a catalog, such as a three-part name or the
catalogattributeSequence
options@GenericGeneratorand@TableGeneratorgenerators, custom generators that use an@IdGeneratorTypeannotation, and named legacy generators such asidentity,table, orincrementMapping an entity onto the
hibernate_sequencescollectioninsert ... selectstatements that require inline allocation of generated IDs
Composite Primary Keys
To key an entity on more than one field, define a composite primary key. Create a plain @Embeddable class or record that holds the key components. Then, annotate your entity's identifier field with the @jakarta.persistence.EmbeddedId annotation.
The following BookId embeddable defines a key that consists of a publisherId component and a bookNo component:
public record BookId(long publisherId, long bookNo) {}
The following Book entity uses BookId as its primary key:
public class Book { private BookId id; private String title; public Book() { } public Book(BookId id, String title) { this.id = id; this.title = title; } // Getter and setter methods }
You must assign composite key values in your application before you persist an entity. The Hibernate ORM extension does not generate composite key values.
Composite Key Storage
The Hibernate ORM extension stores a composite key as an _id sub-document. The preceding Book entity produces documents in the following format:
{ "_id": { "bookNo": 2, "publisherId": 10 }, "title": "My Book" }
The Hibernate ORM extension orders the components of the _id sub-document alphabetically by component name, rather than in the order that you declare them. This order is the same whether you declare the embeddable as a class or as a record.
Important
Component Order Affects Document Matching
MongoDB compares sub-documents by field order, so two _id values that contain the same components in a different order do not match. Because the Hibernate ORM extension always writes components in the same order, this behavior affects you only if you also read or write these documents outside of the Hibernate ORM extension, such as through the MongoDB Java driver.
Composite Key Limitations
The Hibernate ORM extension throws a FeatureNotSupportedException when your application starts if you declare a composite key in any of the following ways:
A non-aggregated identifier, declared either with the
@jakarta.persistence.IdClassannotation or with multiple@Idattributes. Declare the key with@EmbeddedIdinstead.A
@Structaggregate embeddable as the identifier. Use a plain@Embeddableinstead.A component that is not a basic value, such as a nested
@Embeddableor a collection. Every component of a composite key must be a basic value.An association within the identifier, including derived identity that uses the
@jakarta.persistence.MapsIdannotation.
You also cannot compare a whole composite identifier by using an ordering operator such as > or <. Compare individual components instead.
Embedded Data
The Hibernate ORM extension supports embedded documents through Hibernate ORM @Embeddable annotations. With embedded documents, you can create One-to-Many, Many-to-One, and One-to-One relationships within MongoDB documents. This format is ideal for representing data that is frequently accessed together.
To represent embedded documents, use the @Struct and @Embeddable annotations on a class to create a @Struct aggregate embeddable. Then, include the embeddable type in your parent entity as a field. The Hibernate ORM extension supports embedding single objects, arrays, and collections of embeddables.
Tip
To learn more about @Struct aggregate embeddables, see @Struct aggregate embeddable mapping in the Hibernate ORM documentation.
One-to-One Relationships
A One-to-One relationship is when a record in one database is associated with exactly one record in another database. In MongoDB, you can create a collection with an embedded document field to model a One-to-One relationship. The Hibernate ORM extension allows you to create embedded document fields by using @Struct aggregate embeddables.
The example defines a field with a @Struct aggregate embeddable type in an entity similar to the Define an Entity example in this guide. The sample Movie.java entity class includes the following information:
@Entityand@Tableannotations that define the entity and map it to themoviescollection@Idand@ObjectIdGeneratorannotations that designate theidfield as the primary keyString field that represents the movie's title
@Structaggregate embeddable fields that represent movie awards and studio information
The following example represents a One-to-One relationship because each Movie entity is associated with one Awards embeddable and one Studio embeddable:
public class Movie { private ObjectId id; private String title; private Awards awards; private Studio studio; public Movie(String title, Awards awards, Studio studio) { this.title = title; this.awards = awards; this.studio = studio; } public Movie() { } // Getter and setter methods }
The following sample code creates an Awards @Struct aggregate embeddable:
public class Awards { private int wins; private int nominations; private String text; public Awards(int wins, int nominations, String text) { this.wins = wins; this.nominations = nominations; this.text = text; } public Awards() { } // Getter and setter methods }
The following sample code creates a Studio @Struct aggregate embeddable:
public class Studio { private String name; private String location; private int foundedYear; public Studio(String name, String location, int foundedYear) { this.name = name; this.location = location; this.foundedYear = foundedYear; } public Studio() { } // Getter and setter methods }
One-to-Many Relationships
A One-to-Many relationship is when a record in one database is associated with many records in another database. In MongoDB, you can define a collection field that stores a list of embedded documents to model a One-to-Many relationship. The Hibernate ORM extension allows you to create embedded document fields by using a list of @Struct aggregate embeddables.
The example defines a field that stores a list of @Struct aggregate embeddables in an entity similar to the Define an Entity Example in this guide. The sample Movie.java entity class includes the following information:
@Entityand@Tableannotations that define the entity and map it to themoviescollection@Idand@ObjectIdGeneratorannotations that designate theidfield as the primary keyString field that represents the movie's title
List field that stores multiple
Writer@Structaggregate embeddables, which represents writer information
The following example represents a One-to-Many relationship because each Movie entity is associated with multiple Writer embeddables:
public class Movie { private ObjectId id; private String title; private List<Writer> writers; public Movie(String title, List<Writer> writers) { this.title = title; this.writers = writers; } public Movie() { } // Getter and setter methods }
The following sample code creates a Writer @Struct aggregate embeddable:
public class Writer { private String name; public Writer() { } public Writer(String name) { this.name = name; } // Getter and setter methods }
Nested Embeddables
You can nest a flattened embeddable inside a @Struct aggregate embeddable. A flattened embeddable is a class that includes an @Embeddable annotation but not a @Struct annotation. The Hibernate ORM extension stores the fields of a flattened embeddable as fields of the parent embedded document instead of as a separate nested document.
The following sample code creates a Studio @Struct aggregate embeddable that includes an Address flattened embeddable as a field:
public class Studio { private String name; private Address address; public Studio() { } public Studio(String name, Address address) { this.name = name; this.address = address; } // Getter and setter methods }
The following sample code creates the Address flattened embeddable. The class omits the @Struct annotation:
public class Address { private String city; private String country; public Address() { } public Address(String city, String country) { this.city = city; this.country = country; } // Getter and setter methods }
When you persist an entity that includes a Studio field, the Address fields become fields of the Studio field's embedded document. The following example document has a Studio field named studio that stores the fields of its Address flattened embeddable:
{ "_id": { "$oid": "..." }, "title": "Breathless", "studio": { "name": "Les Films Impéria", "city": "Paris", "country": "France" } }
Additional Information
To learn how to map a class hierarchy to a MongoDB collection, see the Map an Entity Inheritance Hierarchy guide.
To learn how to use your entities to run database operations, see the following guides in the Interact with Data section:
To learn more about Hibernate ORM fields, see the Mapping types section in the Hibernate ORM documentation.
To learn more about Hibernate ORM entities, see POJO Models in the Hibernate ORM documentation.