For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.
See how MongoDB 9.0 delivers up to 2x higher throughput.
MongoDB Branding Shape
Register now >
Docs Menu

Create Entities to Represent Collections

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 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

null

null

Represents a null value or absence of data.

Binary

byte[]

Stores binary data with subtype 0.

String

char, java.lang.Character, java.lang.String, char[], java.time.ZoneId, java.time.ZoneOffset, or java.util.TimeZone

Stores UTF-8 encoded string values. The ZoneId and TimeZone types store their ID, such as Europe/Paris. The ZoneOffset type stores its offset ID, such as +02:00.

Int32

int, java.lang.Integer, or java.time.Year

Stores 32-bit signed integers.

Int64

long or java.lang.Long

Stores 64-bit signed integers.

Double

double or java.lang.Double

Stores floating-point values.

Boolean

boolean or java.lang.Boolean

Stores true or false values.

Decimal128

java.math.BigDecimal or java.time.Duration

Stores 28-bit decimal values. java.time.Duration values store the duration in nanoseconds.

ObjectId

org.bson.types.ObjectId

Stores unique 12-byte identifiers that MongoDB uses as primary keys.

Date

java.time.Instant

Stores dates and times as milliseconds since the Unix epoch.

Object

@org.hibernate.annotations.Struct aggregate embeddable

Stores embedded documents with field values mapped according to their respective types. @Struct aggregate embeddables might also contain array or Collection attributes.

Array

Array, java.util.Collection (or subtype) of supported types

Stores array values with elements mapped according to their respective types. Character arrays require setting the hibernate.type.wrapper_array_handling configuration property.

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.

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

java.util.Calendar, java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.time.LocalTime, java.time.LocalDateTime, java.time.ZonedDateTime, java.time.OffsetTime, java.time.OffsetDateTime

Use java.time.Instant.

BSON Values

org.bson.types.BSONTimestamp, org.bson.types.Binary, org.bson.types.Code, org.bson.types.CodeWithScope, org.bson.types.CodeWScope, org.bson.types.MinKey, org.bson.types.MaxKey, org.bson.types.Symbol, org.bson.types.Decimal128

Use byte[] for binary data and java.math.BigDecimal for decimal values. The other types have no equivalent.

BSON Documents

org.bson.Document, org.bson.BsonDocument, org.bson.RawBsonDocument, org.bson.BsonDocumentWrapper

Use an @org.hibernate.annotations.Struct aggregate embeddable.

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:

@Entity
@Table(name = "<collection name>")
public class <EntityName> {
@Id
// 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.

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:

@Entity
@Table(schema = "<schema name>", name = "<collection name>")
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.

This sample Movie.java entity class defines a Movie entity that includes the following information:

  • @Entity annotation that marks the class as a Hibernate ORM entity

  • @Table annotation that maps the entity to the movies collection from the Atlas sample datasets

  • @Id and @ObjectIdGenerator annotations that designate the id field as the primary key and configure automatic ObjectId generation

    Tip

    Primary Key Values

    This example specifies the ObjectId field as the entity's primary key, but you can also set String or int fields as the primary key by using the @Id annotation. 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;
@Entity
@Table(name = "movies")
public class Movie {
@Id
@ObjectIdGenerator
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.

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.

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:

@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "movies_SEQ"
)
@SequenceGenerator(
name = "movies_SEQ",
sequenceName = "movies_SEQ",
allocationSize = 50
)
private Long id;

The annotations control how the Hibernate ORM extension creates the ID:

  • @GeneratedValue tells the Hibernate ORM extension to create the value of the id field. Its strategy and generator attributes define how the extension creates the ID:

    • strategy: AUTO or SEQUENCE. With AUTO, the Hibernate ORM extension uses a sequence, and you don't have to declare a @SequenceGenerator. With SEQUENCE, the Hibernate ORM extension uses the sequence generator named by the generator attribute.

    • generator: The name of the @SequenceGenerator to use. If you omit this attribute, the Hibernate ORM extension names the sequence after the entity's table, such as movies_SEQ for the movies table.

  • @SequenceGenerator defines the sequence generator:

    • name: The name that the @GeneratedValue generator attribute references.

    • sequenceName: The name of the counter document. If you omit it, the Hibernate ORM extension uses the generator's name.

    • initialValue: The value that the first generated ID starts from. Defaults to 1.

    • allocationSize: The number of IDs reserved in each block.

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:

  • _id is the sequence name.

  • next_value is the counter value that the Hibernate ORM extension advances to produce the next IDs. It must match the initialValue of the sequence generator, which defaults to 1.

  • increment is the number of IDs reserved at one time. It must match the sequence generator's allocationSize value. If it doesn't, the SessionFactory fails 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.

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 the SessionFactory closes.

  • create-drop: Creates the counter documents when the SessionFactory opens and drops them when it closes.

The following example uses create:

jakarta.persistence.schema-generation.database.action=create

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.

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());

The Hibernate ORM extension does not support the following sequence-related strategies, types, and configurations:

  • IDENTITY and TABLE generation strategies

  • BigInteger and BigDecimal generated identifier types

  • Sequence names or schemas that contain a . character

  • Sequence names qualified by a catalog, such as a three-part name or the catalog attribute

  • Sequence options

  • @GenericGenerator and @TableGenerator generators, custom generators that use an @IdGeneratorType annotation, and named legacy generators such as identity, table, or increment

  • Mapping an entity onto the hibernate_sequences collection

  • insert ... select statements that require inline allocation of generated IDs

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:

@Embeddable
public record BookId(long publisherId, long bookNo) {}

The following Book entity uses BookId as its primary key:

@Entity(name = "Book")
@Table(name = "books")
public class Book {
@EmbeddedId
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.

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.

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.IdClass annotation or with multiple @Id attributes. Declare the key with @EmbeddedId instead.

  • A @Struct aggregate embeddable as the identifier. Use a plain @Embeddable instead.

  • A component that is not a basic value, such as a nested @Embeddable or 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.MapsId annotation.

You also cannot compare a whole composite identifier by using an ordering operator such as > or <. Compare individual components instead.

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.

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:

  • @Entity and @Table annotations that define the entity and map it to the movies collection

  • @Id and @ObjectIdGenerator annotations that designate the id field as the primary key

  • String field that represents the movie's title

  • @Struct aggregate 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:

@Entity
@Table(name = "movies")
public class Movie {
@Id
@ObjectIdGenerator
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:

@Embeddable
@Struct(name = "Awards")
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:

@Embeddable
@Struct(name = "Studio")
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
}

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:

  • @Entity and @Table annotations that define the entity and map it to the movies collection

  • @Id and @ObjectIdGenerator annotations that designate the id field as the primary key

  • String field that represents the movie's title

  • List field that stores multiple Writer @Struct aggregate embeddables, which represents writer information

The following example represents a One-to-Many relationship because each Movie entity is associated with multiple Writer embeddables:

@Entity
@Table(name = "movies")
public class Movie {
@Id
@ObjectIdGenerator
@Column(name = "_id")
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:

@Embeddable
@Struct(name = "Writer")
public class Writer {
private String name;
public Writer() {
}
public Writer(String name) {
this.name = name;
}
// Getter and setter methods
}

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:

@Embeddable
@Struct(name = "Studio")
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:

@Embeddable
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"
}
}

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.