OGM-1326 Add example of associations between entities of the same class (#25)

Added an example to the documentation that shows a OneToOne mapping to the same entity. ie. A person has a spouse that is another person.

[[ogm-mongodb]]

== MongoDB

http://www.mongodb.org[MongoDB] is a document oriented datastore
written in C++ with strong emphasis on ease of use.
The nested nature of documents make it a particularly natural fit for most object representations.

This implementation is based upon the MongoDB Java driver.
The currently supported version is {mongodb-version}.

=== Why should I use Hibernate OGM with MongoDB

It is possible that in your project you have some entities that might benefit from MongoDB
dynamic schema, but having a schema makes it possible to obtain better performance because
the datastore can use the information of the schema to apply some optimizations that
wouldn't be otherwise possible.

JPA already has ways to define constraints and indexes and via Hibernate OGM you can
use the same annotations for both your relational and not relational needs.

Hibernate OGM cannot make MongoDB transactional but by using the JPA transaction demarcation
mechanism it can group the operations and flush them to the datastore to
minimize the number of requests.

Another benefit of using Hibernate OGM with MongoDB is that it will also make it possible
to use Hibernate Search out of the box. Hibernate Search brings the power of Lucene
to your project, giving you the ability to run fast google-like searches.

This means that you can query the datastore using:

* JPQL queries (see <<ogm-jpql-query>>)
* MongoDB native queries (see <<ogm-mongodb-queries-native>>)
* Full-text queries (see <<ogm-query-using-hibernate-search>>)

One of Hibernate OGM main goal is to map entities in a "natural" way, this means that your
datastore will still be accessible in case you need to use other tools or want to run
native queries occasionally.

=== Configuring MongoDB

Configuring Hibernate OGM to use MongoDb is easy:

* Add the MongoDB module and driver to the classpath
* provide the MongoDB URL to Hibernate OGM

==== Adding MongoDB dependencies

To add the dependencies via Maven, add the following module:

[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-mongodb</artifactId>
    <version>{hibernate-ogm-version}</version>
</dependency>
----

This will pull the MongoDB driver transparently.

If you're not using a dependency management tool,
copy all the dependencies from the distribution in the directories:

* `/lib/required`
* `/lib/mongodb`
* Optionally - depending on your container - you might need some of the jars from `/lib/provided`

MongoDB does not require Hibernate Search for the execution of JPQL or HQL queries.

==== MongoDB specific configuration properties

To get started quickly, pay attention to the following options:

* `hibernate.ogm.datastore.provider`
* `hibernate.ogm.datastore.host`
* `hibernate.ogm.datastore.database`

And we should have you running.
The following properties are available to configure MongoDB support:

.MongoDB datastore configuration properties
hibernate.ogm.datastore.provider::
To use MongoDB as a datastore provider, this property must be set to `mongodb`
hibernate.ogm.option.configurator::
The fully-qualified class name or an instance of a programmatic option configurator (see <<ogm-mongodb-programmatic-configuration>>)
hibernate.ogm.datastore.host::
The hostname and port of the MongoDB instance.
The optional port is concatenated to the host and separated by a colon.
When using replica sets, you can define the various servers in a comma separated list of hosts and ports.
Let's see a few valid examples:

* `mongodb.example.com`
* `mongodb.example.com:27018`
* `2001:db8::ff00:42:8329` (IPv6)

* `[2001:db8::ff00:42:8329]:27018` (IPv6 with port requires the IPv6 to be surrounded by square brackets)
* `www.example.com, www2.example.com:123, 192.0.2.1, 192.0.2.2:123, 2001:db8::ff00:42:8329, [2001:db8::ff00:42:8329]:123` (replica set)
+
The default value is `127.0.0.1:27017`. If left undefined, the default port is `27017`.
hibernate.ogm.datastore.port::
Deprecated: use `hibernate.ogm.datastore.host`.
The port used by the MongoDB instance.
Ignored when multiple hosts are defined.
The default value is `27017`.
hibernate.ogm.datastore.database::
The database to connect to. This property has no default value.
hibernate.ogm.datastore.create_database::
If set to true, the database will be created if it doesn't exist.
This property default value is false.
hibernate.ogm.datastore.username::
The username used when connecting to the MongoDB server.
This property has no default value.
hibernate.ogm.datastore.password::
The password used to connect to the MongoDB server.
This property has no default value.
This property is ignored if the username isn't specified.
hibernate.ogm.error_handler::
The fully-qualified class name, class object or an instance of `ErrorHandler` to get notified upon errors during flushes (see <<ogm-api-error-handler>>)
hibernate.ogm.mongodb.driver.*::
Defines a prefix for all options which should be passed through to the MongoDB driver.
For available options refer to the JavaDocs of link:http://api.mongodb.org/java/3.0/com/mongodb/MongoClientOptions.Builder.html[MongoClientOptions.Builder]. All `String`, `int` and `boolean` properties
can be set, eg `hibernate.ogm.mongodb.driver.serverSelectionTimeout`.
hibernate.ogm.mongodb.authentication_database::
Defines the name of the authentication database, default value is _admin_.
hibernate.ogm.mongodb.authentication_mechanism::
Defines the authentication mechanism to use. Possible values are:

* `BEST`: Handshakes with the server to find the best authentication mechanism.
* `SCRAM_SHA_1`: The SCRAM SHA 1 Challenge Response mechanism as described in this link:http://tools.ietf.org/html/rfc5802[RFC].
* `MONGODB_CR`: The MongoDB Challenge Response mechanism (deprecated since MongoDB 3)
* `GSSAPI`: The GSSAPI mechanism. See the http://tools.ietf.org/html/rfc4752[RFC]
* `MONGODB_X509`: The MongoDB X.509
* `PLAIN`: The PLAIN mechanism.  See the http://www.ietf.org/rfc/rfc4616.txt[RFC]
hibernate.ogm.datastore.document.association_storage::
Defines the way OGM stores association information in MongoDB.
The following two strategies exist (values of the `org.hibernate.ogm.datastore.document.options.AssociationStorageType` enum):

* `IN_ENTITY`: store association information within the entity
* `ASSOCIATION_DOCUMENT`: store association information in a dedicated document per association

+
`IN_ENTITY` is the default and recommended option
unless the association navigation data is much bigger than the core of the document and leads to performance degradation.
hibernate.ogm.mongodb.association_document_storage::
Defines how to store assocation documents (applies only if the `ASSOCIATION_DOCUMENT`
association storage strategy is used).
Possible strategies are (values of the `org.hibernate.ogm.datastore.mongodb.options.AssociationDocumentStorageType` enum):

* `GLOBAL_COLLECTION` (default): stores the association information in a unique MongoDB collection for all associations
* `COLLECTION_PER_ASSOCIATION` stores the association in a dedicated MongoDB collection per association

hibernate.ogm.datastore.document.map_storage::
Defines the way OGM stores the contents of map-typed associations in MongoDB.
The following two strategies exist (values of the `org.hibernate.ogm.datastore.document.options.MapStorageType` enum):

* `BY_KEY`: map-typed associations with a single key column which is of type `String` will be stored as a sub-document,
organized by the given key; Not applicable for other types of key columns, in which case always `AS_LIST` will be used
* `AS_LIST`: map-typed associations will be stored as an array containing a sub-document for each map entry.
All key and value columns will be contained within the array elements

hibernate.ogm.mongodb.write_concern::
Defines the write concern setting to be applied when issuing writes against the MongoDB datastore.
Possible settings are (values of the `WriteConcernType` enum):
`ACKNOWLEDGED`, `UNACKNOWLEDGED`, `FSYNCED`, `JOURNALED`, `REPLICA_ACKNOWLEDGED`, `MAJORITY` and `CUSTOM`.
When set to `CUSTOM`, a custom `WriteConcern` implementation type has to be specified.
+
This option is case insensitive and the default value is `ACKNOWLEDGED`.
hibernate.ogm.mongodb.write_concern_type::
Specifies a custom `WriteConcern` implementation type (fully-qualified name, class object or instance).
This is useful in cases where the pre-defined configurations are not sufficient,
e.g. if you want to ensure that writes are propagated to a specific number of replicas or given "tag set".
Only takes effect if `hibernate.ogm.mongodb.write_concern` is set to `CUSTOM`.
hibernate.ogm.mongodb.read_preference::
Specifies the `ReadPreference` to be applied when issuing reads against the MongoDB datastore.
Possible settings are (values of the `ReadPreferenceType` enum):
`PRIMARY`, `PRIMARY_PREFERRED`, `SECONDARY`, `SECONDARY_PREFERRED` and `NEAREST`.
It's currently not possible to plug in custom read preference types.
If you're interested in such a feature, please let us know.

For more information, please refer to the
http://api.mongodb.org/java/current/com/mongodb/WriteConcern.html[official documentation].

[NOTE]
====
When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via `org.hibernate.ogm.datastore.mongodb.MongoDBProperties`
when specifying the configuration properties listed above.

Common properties shared between stores are declared on `OgmProperties`
(a super interface of `MongoDBProperties`).

For maximum portability between stores, use the most generic interface possible.
====

[[ogm-mongodb-annotation-configuration]]
==== Annotation based configuration

Hibernate OGM allows to configure store-specific options via Java annotations.
You can override global configurations for a specific entity or even a specify property
by virtue of the location where you place that annotation.

When working with the MongoDB backend, you can specify the following settings:

* the write concern for entities and associations using the `@WriteConcern` annotation
* the read preference for entities and associations using the `@ReadPreference` annotation
* a strategy for storing associations using the `@AssociationStorage` and `@AssociationDocumentStorage` annotations
* a strategy for storing the contents of map-typed associations using the `@MapStorage` annotation

Refer to <<mongodb-associations> to learn more about the options related to storing associations.

The following shows an example:

.Configuring the association storage strategy using annotations
====
[source, JAVA]
----
@Entity
@WriteConcern(WriteConcernType.JOURNALED)
@ReadPreference(ReadPreferenceType.PRIMARY_PREFERRED)
@AssociationStorage(AssociationStorageType.ASSOCIATION_DOCUMENT)
@AssociationDocumentStorage(AssociationDocumentStorageType.COLLECTION_PER_ASSOCIATION)
@MapStorage(MapStorageType.AS_LIST)
public class Zoo {

    @OneToMany
    private Set<Animal> animals;

    @OneToMany
    private Set<Person> employees;

    @OneToMany
    @AssociationStorage(AssociationStorageType.IN_ENTITY)
    private Set<Person> visitors;

    // getters, setters ...
}
----
====

The `@WriteConcern` annotation on the entity level expresses that all writes should be done using the `JOURNALED` setting.
Similarly, the `@ReadPreference` annotation advices the engine to preferably read that entity from the primary node if possible.
The other two annotations on the type-level specify that all associations of the `Zoo`
class should be stored in separate assocation documents, using a dedicated collection per association.
This setting applies to the `animals` and `employees` associations.
Only the elements of the `visitors` association will be stored in the document of the corresponding `Zoo` entity
as per the configuration of that specific property which takes precedence over the entity-level configuration.

[[ogm-mongodb-programmatic-configuration]]
==== Programmatic configuration

In addition to the annotation mechanism,
Hibernate OGM also provides a programmatic API for applying store-specific configuration options.
This can be useful if you can't modify certain entity types or
don't want to add store-specific configuration annotations to them.
The API allows set options in a type-safe fashion on the global, entity and property levels.

When working with MongoDB, you can currently configure the following options using the API:

* write concern
* read preference
* association storage strategy
* association document storage strategy
* strategy for storing the contents of map-typed associations

To set these options via the API, you need to create an `OptionConfigurator` implementation
as shown in the following example:

.Example of an option configurator
====
[source, JAVA]
----
public class MyOptionConfigurator extends OptionConfigurator {

    @Override
    public void configure(Configurable configurable) {
        configurable.configureOptionsFor( MongoDB.class )
            .writeConcern( WriteConcernType.REPLICA_ACKNOWLEDGED )
            .readPreference( ReadPreferenceType.NEAREST )
            .entity( Zoo.class )
                .associationStorage( AssociationStorageType.ASSOCIATION_DOCUMENT )
                .associationDocumentStorage( AssociationDocumentStorageType.COLLECTION_PER_ASSOCIATION )
                .mapStorage( MapStorageType.ASLIST )
                .property( "animals", ElementType.FIELD )
                    .associationStorage( AssociationStorageType.IN_ENTITY )
            .entity( Animal.class )
                .writeConcern( new RequiringReplicaCountOf( 3 ) )
                .associationStorage( AssociationStorageType.ASSOCIATION_DOCUMENT );
    }
}
----
====

The call to `configureOptionsFor()`, passing the store-specific identifier type `MongoDB`,
provides the entry point into the API. Following the fluent API pattern, you then can configure
global options (`writeConcern()`, `readPreference()`) and navigate to single entities or properties to apply options
specific to these (`associationStorage()` etc.).
The call to `writeConcern()`  for the `Animal`  entity shows how a specific write concern type can be used.
Here `RequiringReplicaCountOf` is a custom implementation of `WriteConcern` which ensures
that writes are propagated to a given number of replicas before a write is acknowledged.

Options given on the property level precede entity-level options. So e.g. the `animals` association of the `Zoo`
class would be stored using the in entity strategy, while all other associations of the `Zoo` entity would
be stored using separate association documents.

Similarly, entity-level options take precedence over options given on the global level.
Global-level options specified via the API complement the settings given via configuration properties.
In case a setting is given via a configuration property and the API at the same time,
the latter takes precedence.

Note that for a given level (property, entity, global),
an option set via annotations is overridden by the same option set programmatically.
This allows you to change settings in a more flexible way if required.

To register an option configurator, specify its class name using the `hibernate.ogm.option.configurator` property.
When bootstrapping a session factory or entity manager factory programmatically,
you also can pass in an `OptionConfigurator` instance or the class object representing the configurator type.

[[ogm-mongodb-storage-principles]]
=== Storage principles

Hibernate OGM tries to make the mapping to the underlying datastore as natural as possible
so that third party applications not using Hibernate OGM can still read
and update the same datastore.
We worked particularly hard on the MongoDB model
to offer various classic mappings between your object model
and the MongoDB documents.

To describe things simply, each entity is stored as a MongoDB document.
This document is stored in a MongoDB collection named after the entity type.
The navigational information for each association from one entity to (a set of) entity
is stored in the document representing the entity we are departing from.

[[mongodb-built-in-types]]
==== Properties and built-in types

Each entity is represented by a document.
Each property or more precisely column is represented by a field in this document,
the field name being the column name.

Hibernate OGM supports by default the following property types:

* `java.lang.String`

[source, JSON]
----
  { "text" : "Hello world!" }
----

* `java.lang.Character` (or char primitive)

[source, JSON]
----
  { "delimiter" : "/" }
----

* `java.lang.Boolean` (or boolean primitive)

[source, JSON]
----
  { "favorite" : true } # default mapping
  { "favorite" : "T" } # if @Type(type = "true_false") is given
  { "favorite" : "Y" } # if @Type(type = "yes_no") is given
  { "favorite" : 1 } # if @Type(type = "numeric_boolean") is given
----

* `java.lang.Byte` (or byte primitive)

[source, JSON]
----
  { "display_mask" : "70" }
----

* `java.lang.Byte[]` (or byte[])

[source, JSON]
----
  { "pdfAsBytes" : BinData(0,"MTIzNDU=") }
----

* `java.lang.Short` (or short primitive)

[source, JSON]
----
  { "urlPort" : 80 }
----

* `java.lang.Integer` (or integer primitive)

[source, JSON]
----
  { "stockCount" : 12309 }
----

* `java.lang.Long` (or long primitive)

[source, JSON]
----
  { "userId" : NumberLong("-6718902786625749549") }
----

* `java.lang.Float` (or float primitive)

[source, JSON]
----
  { "visitRatio" : 10.39 }
----

* `java.lang.Double` (or double primitive)

[source, JSON]
----
  { "tax_percentage" : 12.34 }
----

* `java.math.BigDecimal`

[source, JSON]
----
  { "site_weight" : "21.77" }
----

* `java.math.BigInteger`

[source, JSON]
----
  { "site_weight" : "444" }
----

* `java.util.Calendar`

[source, JSON]
----
  { "creation" : "2014/11/03 16:19:49:283 +0000" }
----

* `java.util.Date`

[source, JSON]
----
  { "last_update" : ISODate("2014-11-03T16:19:49.283Z") }
----

* `java.util.UUID`

[source, JSON]
----
  { "serialNumber" : "71f5713d-69c4-4b62-ad15-aed8ce8d10e0" }
----

* `java.util.URL`

[source, JSON]
----
  { "url" : "http://www.hibernate.org/" }
----

* `org.bson.types.ObjectId`

[source, JSON]
----
  { "object_id" : ObjectId("547d9b40e62048750f25ef77") }
----

[NOTE]
====
Hibernate OGM doesn't store null values in MongoDB,
setting a value to null is the same as removing the field
in the corresponding object in the db.

This can have consequences when it comes to queries on null value.
====

==== Entities

Entities are stored as MongoDB documents and not as BLOBs:
each entity property will be translated into a document field.
You can use `@Table` and `@Column` annotations
to rename respectively the collection the document is stored in
and the document's field a property is persisted in.

.Default JPA mapping for an entity
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
// Stored in the Collection "News"
{
    "_id" : "1234-5678-0123-4567",
    "title": "On the merits of NoSQL",
}
----
====

.Rename field and collection using @Table and @Column
====
[source, JAVA]
----
@Entity
// Overrides the collection name
@Table(name = "News_Collection")
public class News {

    @Id
    private String id;

    // Overrides the field name
    @Column(name = "headline")
    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
// Stored in the Collection "News"
{
    "_id" : "1234-5678-0123-4567",
    "headline": "On the merits of NoSQL",
}
----
====

===== Identifiers

[NOTE]
====
Hibernate OGM always store identifiers using the `_id` field of a MongoDB document ignoring
the name of the property in the entity.

That's a good thing as MongoDB has special treatment and expectation of the property `_id`.
====

An identifier type may be one of the <<mongodb-built-in-types,built-in types>>
or a more complex type represented by an embedded class.
When you use a built-in type, the identifier is mapped like a regular property.
When you use an embedded class, then the `_id` is representing a nested document
containing the embedded class properties.

.Define an identifier as a primitive type
====
[source, JAVA]
----
@Entity
public class Bookmark {

    @Id
    private String id;

    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
{
  "_id" : "bookmark_1"
  "title" : "Hibernate OGM documentation"
}
----
====

.Define an identifier using @EmbeddedId
====
[source, JAVA]
----
@Embeddable
public class NewsID implements Serializable {

    private String title;
    private String author;

    // getters, setters ...
}

@Entity
public class News {

    @EmbeddedId
    private NewsID newsId;
    private String content;

    // getters, setters ...
}
----

News collection as JSON in MongoDB

[source, JSON]
----

{
  "_id" : {
      "author" : "Guillaume",
      "title" : "How to use Hibernate OGM ?"
  },
  "content" : "Simple, just like ORM but with a NoSQL database"
}

----
====

Generally, it is recommended though to work with MongoDB's object id data type.
This will facilitate the integration with other applications expecting that common MongoDB id type.
To do so, you have two options:

* Define your id property as `org.bson.types.ObjectId`
* Define your id property as `String` and annotate it with `@Type(type="objectid")`

In both cases the id will be stored as native `ObjectId` in the datastore.

.Define an id as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private ObjectId id;

    private String title;

    // getters, setters ...
}
----
====

.Define an id of type String as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    @Type(type = "objectid")
    private String id;

    private String title;

    // getters, setters ...
}
----
====

===== Identifier generation strategies

You can assign id values yourself or let Hibernate OGM generate the value using the
`@GeneratedValue` annotation.

There are 4 different strategies:

1. <<mongodb-identity-id-generation-strategy, IDENTITY>> (suggested)
2. <<mongodb-table-id-generation-strategy, TABLE>>
3. <<mongodb-sequence-id-generation-strategy, SEQUENCE>>
4. <<mongodb-auto-id-generation-strategy, AUTO>>

[[mongodb-identity-id-generation-strategy]]
*1) IDENTITY generation strategy*

The preferable strategy, Hibernate OGM will create the identifier upon insertion.
To apply this strategy the id must be one of the following:

* annotated with `@Type(type="objectid")`
* `org.bson.types.ObjectId`

like in the following examples:

.Define an id of type String as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Type(type = "objectid")
    private String id;

    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : ObjectId("5425448830048b67064d40b1"),
    "title" : "Exciting News"
}
----
====

.Define an id as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private ObjectId id;

    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : ObjectId("5425448830048b67064d40b1"),
    "title" : "Exciting News"
}
----
====

[[mongodb-table-id-generation-strategy]]
*2) TABLE generation strategy*

.Id generation strategy TABLE using default values
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    private String name;

    // getters, setters ...
}

----

GuitarPlayer collection

[source, JSON]
----
{
    "_id" : NumberLong(1),
    "name" : "Buck Cherry"
}
----

hibernate_sequences collection

[source, JSON]
----
{
    "_id" : "GuitarPlayer",
    "next_val" : 101
}
----
====

.Id generation strategy TABLE using a custom table
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "guitarGen")
    @TableGenerator(
        name = "guitarGen",
        table = "GuitarPlayerSequence",
        pkColumnValue = "guitarPlayer",
        valueColumnName = "nextGuitarPlayerId"
    )
    private long id;

    // getters, setters ...
}

----

GuitarPlayer collection

[source, JSON]
----
{
    "_id" : NumberLong(1),
    "name" : "Buck Cherry"
}
----

GuitarPlayerSequence collection

[source, JSON]
----
{
    "_id" : "guitarPlayer",
    "nextGuitarPlayerId" : 2
}
----
====

*3) SEQUENCE generation strategy*

[[mongodb-sequence-id-generation-strategy]]
.SEQUENCE id generation strategy using default values
====
[source, JAVA]
----
@Entity
public class Song {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Long id;

  private String title;

  // getters, setters ...
}
----

Song collection

[source, JSON]
----
{
  "_id" : NumberLong(2),
  "title" : "Flower Duet"
}
----

hibernate_sequences collection

[source, JSON]
----
{ "_id" : "song_sequence_name", "next_val" : 21 }
----
====

[[mongodb-sequence-id-generation-strategy-custom]]
.SEQUENCE id generation strategy using custom values
====
[source, JAVA]
----
@Entity
public class Song {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "songSequenceGenerator")
  @SequenceGenerator(
      name = "songSequenceGenerator",
      sequenceName = "song_seq",
      initialValue = 2,
      allocationSize = 20
  )
  private Long id;

  private String title;

  // getters, setters ...
}
----

Song collection

[source, JSON]
----
{
  "_id" : NumberLong(2),
  "title" : "Flower Duet"
}
----

hibernate_sequences collection

[source, JSON]
----
{ "_id" : "song_seq", "next_val" : 42 }
----
====

[[mongodb-auto-id-generation-strategy]]
*4) AUTO generation strategy*

[WARNING]
====
Care must be taken when using the `GenerationType.AUTO` strategy.
When the property `hibernate.id.new_generator_mappings` is set to `false` (default),
it will map to the `IDENTITY` strategy.
As described before, this requires your ids to be of type `ObjectId` or `@Type(type = "objectid") String`.
If `hibernate.id.new_generator_mappings` is set to true, `AUTO` will be mapped to the `TABLE` strategy.
This requires your id to be of a numeric type.

We recommend to not use `AUTO` but one of the explicit strategies (`IDENTITY` or `TABLE`) to avoid
potential misconfigurations.

For more details you can check the issue https://hibernate.atlassian.net/browse/OGM-663[OGM-663].
====

If the property `hibernate.id.new_generator_mappings`  is set to `false`,
`AUTO` will behave as the `IDENTITY` strategy.

If the property `hibernate.id.new_generator_mappings`  is set to `true`,
`AUTO` will behave as the `SEQUENCE` strategy.

.AUTO id generation strategy using default values
====
[source, JAVA]
----
@Entity
public class DistributedRevisionControl {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String name;

  // getters, setters ...
}
----

DistributedRevisionControl collection

[source, JSON]
----
{ "_id" : NumberLong(1), "name" : "Git" }
----

hibernate_sequences collection

[source, JSON]
----
{ "_id" : "hibernate_sequence", "next_val" : 2 }
----
====

.AUTO id generation strategy wih `hibernate.id.new_generator_mappings` set to false and ObjectId
====
[source, JAVA]
----
@Entity
public class Comedian {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private ObjectId id;

  private String name;

  // getters, setters ...
}
----

Comedian collection

[source, JSON]
----
{ "_id" : ObjectId("5458b11693f4add0f90519c5"), "name" : "Louis C.K." }
----
====

.Entity with @EmbeddedId
====
[source, JAVA]
----
@Entity
public class News {

    @EmbeddedId
    private NewsID newsId;

    // getters, setters ...
}

@Embeddable
public class NewsID implements Serializable {

    private String title;
    private String author;

    // getters, setters ...
}
----

Rendered as JSON in MongoDB
[source, JSON]
----
{
    "_id" :{
        "title": "How does Hibernate OGM MongoDB work?",
        "author": "Guillaume"
    }
}
----
====

===== Embedded objects and collections

Hibernate OGM stores elements annotated with `@Embedded` or `@ElementCollection` as nested documents of the owning entity.

.Embedded object
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    @Embedded
    private NewsPaper paper;

    // getters, setters ...
}

@Embeddable
public class NewsPaper {

    private String name;
    private String owner;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : "1234-5678-0123-4567",
    "title": "On the merits of NoSQL",
    "paper": {
        "name": "NoSQL journal of prophecies",
        "owner": "Delphy"
    }
}
----
====

.@ElementCollection with primitive types
====
[source, JAVA]
----
@Entity
public class AccountWithPhone {

    @Id
    private String id;

    @ElementCollection
    private List<String> mobileNumbers;

    // getters, setters ...
}
----

AccountWithPhone collection

[source, JSON]
----
{
    "_id" : "john_account",
    "mobileNumbers" : [ "+1-222-555-0222", "+1-202-555-0333" ]
}
----
====

.@ElementCollection with one attribute
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : "df153180-c6b3-4a4c-a7da-d5de47cf6f00",
    "grandChildren" : [ "Luke", "Leia" ]
}
----
====

The class `GrandChild` has only one attribute `name`,
this means that Hibernate OGM doesn't need to store the name of the attribute.

If the nested document has two or more fields, like in the following example,
Hibernate OGM will store the name of the fields as well.

.@ElementCollection with @OrderColumn
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    @OrderColumn( name = "birth_order" )
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : "e3e1ed4e-c685-4c3f-9a67-a5aeec6ff3ba",
    "grandChildren" :
        [
            {
                "name" : "Luke",
                "birth_order" : 0
            },
            {
                "name" : "Leia",
                "birthorder" : 1
            }
        ]
}
----
====

.@ElementCollection with Map of @Embeddable
====
[source, JAVA]
----
@Entity
public class ForumUser {

	@Id
	private String name;

	@ElementCollection
	private Map<String, JiraIssue> issues = new HashMap<>();

    // getters, setters ...
}

@Embeddable
public class JiraIssue {

	private Integer number;
	private String project;

    // getters, setters ...
}
----

[source, JSON]
----
{
        "_id" : "Jane Doe",
        "issues" : {
                "issueWithNull" : {
                },
                "issue2" : {
                    "number" : 2000,
                    "project" : "OGM"
                },
                "issue1" : {
                    "number" : 1253,
                    "project" : "HSEARCH"
                }
        }
}
----
====

[NOTE]
====
You can override the column name used for a property of an embedded object.
But you need to know that the default column name is the concatenation of the embedding property,
a `.` (dot) and the embedded property (recursively for several levels of embedded objects).

The MongoDB datastore treats dots specifically as it transforms them into nested documents.
If you want to override one column name and still keep the nested structure, don't forget the dots.

That's a bit abstract, so let's use an example.

[source, JAVA]
----
@Entity
class Order {
    @Id String number;
    User user;
    Address shipping;
    @AttributeOverrides({
        @AttributeOverride(name="name", column=@Column(name="delivery.provider"),
        @AttributeOverride(name="expectedDelaysInDays", column=@Column(name="delivery.delays")
    })
    DeliveryProvider deliveryProvider;
    CreditCardType cardType;
}

// default columns
@Embedded
class User {
    String firstname;
    String lastname;
}

// override one column
@Embeddable
public Address {
    String street;
    @Column(name="shipping.dest_city")
    String city;
}

// both columns overridden from the embedding side
@Embeddable
public DeliveryProvider {
    String name;
    Integer expectedDelaysInDays;
}

// do not use dots in the overriding
// and mix levels (bad form)
@Embedded
class CreditCardType {
    String merchant;
    @Column(name="network")
    String network;
}
----

[source, JSON]
----
{
    "_id": "123RF33",
    "user": {
        "firstname": "Emmanuel",
        "lastname": "Bernard"
    },
    "shipping": {
        "street": "1 av des Champs Elysées",
        "dest_city": "Paris"
    },
    "delivery": {
        "provider": "Santa Claus Inc.",
        "delays": "1"
    }
    "network": "VISA",
    "cardType: {
        "merchant": "Amazon"
    }
}
----

If you share the same embeddable in different places, you can use JPA's `@AttributeOverride`
to override columns from the embedding side.
This is the case of `DeliveryProvider` in our example.

If you omit the dot in one of the columns, this column will not be part of the nested document.
This is demonstrated by the `CreditCardType`.
We advise you against it.
Like crossing streams, it is bad form.
This approach might not be supported in the future.
====

[[mongodb-associations]]
==== Associations

Hibernate OGM MongoDB proposes three strategies to store navigation information for associations.
The three possible strategies are:

* <<mongodb-in-entity-strategy, IN_ENTITY>> (default)
* <<mongodb-association-document-strategy, ASSOCIATION_DOCUMENT>>, using a global collection for all associations
* <<mongodb-collection-per-association-strategy, COLLECTION_PER_ASSOCIATION>>, using a dedicated collection for each association

To switch between these strategies, use of the three approaches to options:

* annotate your entity with `@AssocationStorage` and `@AssociationDocumentStorage` annotations (see <<ogm-mongodb-annotation-configuration>>),
* use the API for programmatic configuration (see <<ogm-mongodb-programmatic-configuration>>)
* or specify a default strategy via the `hibernate.ogm.datastore.document.association_storage` and
`hibernate.ogm.mongodb.association_document_storage` configuration properties.

[[mongodb-in-entity-strategy]]
===== In Entity strategy

* <<mongodb-in-entity-to-one-associations, *-to-one associations>>
* <<mongodb-in-entity-to-many-associations, *-to-many associations>>

In this strategy, Hibernate OGM stores the id(s) of the associated entity(ies)
into the entity document itself.
This field stores the id value for to-one associations and an array of id values for to-many associations.
An embedded id will be represented by a nested document.
For indexed collections (i.e. `List` or `Map`), the index will be stored along the id.

[NOTE]
====
When using this strategy the annotations `@JoinTable` will be ignored because no collection is created
for associations.

You can use `@JoinColumn` to change the name of the field that stores the foreign key (as an example, see
<<mongodb-in-entity-one-to-one-join-column>>).
====

[[mongodb-in-entity-to-one-associations]]
===== To-one associations

.Unidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Vehicle {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    private Vehicle vehicle;

    // getters, setters ...
}
----

[source, JSON]
----
{
  "_id" : "V_01",
  "brand" : "Mercedes"
}
----

Wheel collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "W001",
  "diameter" : 0,
  "vehicle_id" : "V_01"
}
----
====

[[mongodb-in-entity-one-to-one-join-column]]
.Unidirectional one-to-one with @JoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicle {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @JoinColumn( name = "part_of" )
    private Vehicle vehicle;

    // getters, setters ...
}
----

[source, JSON]
----
{
  "_id" : "V_01",
  "brand" : "Mercedes"
}
----

Wheel collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "W001",
  "diameter" : 0,
  "part_of" : "V_01"
}
----
====

In a true one-to-one association, it is possible to share the same id between the two entities
and therefore a foreign key is not required. You can see how to map this type of association in
the following example:

.Unidirectional one-to-one with @MapsId and @PrimaryKeyJoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicle {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @PrimaryKeyJoinColumn
    @MapsId
    private Vehicle vehicle;

    // getters, setters ...
}
----

Vehicle collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "V_01",
  "brand" : "Mercedes"
}
----

Wheel collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "V_01",
  "diameter" : 0,
}
----
====

.Bidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Husband {

    @Id
    private String id;
    private String name;

    @OneToOne
    private Wife wife;

    // getters, setters ...
}

@Entity
public class Wife {

    @Id
    private String id;
    private String name;

    @OneToOne
    private Husband husband;

    // getters, setters ...
}
----

Husband collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "alex",
  "name" : "Alex",
  "wife" : "bea"
}
----

Wife collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "bea",
  "name" : "Bea",
  "husband" : "alex"
}
----
====

.Bidirectional one-to-one (Mapping to the same Entity)
====
[source, JAVA]
----
@Entity
public class Person {

    @Id
    private String id;
    private String name;

    @OneToOne
    private Person spouse;

    // getters, setters ...
}
----

Person (husband) collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "alex",
  "name" : "Alex",
  "spouse" : "bea"
}
----

Person (wife) collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "bea",
  "name" : "Bea",
  "spouse" : "alex"
}
----
====

.Unidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class JavaUserGroup {

    @Id
    private String jugId;
    private String name;

    // getters, setters ...
}

@Entity
public class Member {

    @Id
    private String id;
    private String name;

    @ManyToOne
    private JavaUserGroup memberOf;

    // getters, setters ...
}
----

JavaUserGroup collection as JSON in MongoDB

[source, JSON]
----
{
    "_id" : "summer_camp",
    "name" : "JUG Summer Camp"
}
----

Member collection as JSON in MongoDB

[source, JSON]
----
{
    "_id" : "jerome",
    "name" : "Jerome"
    "memberOf_jugId" : "summer_camp"
}
{
    "_id" : "emmanuel",
    "name" : "Emmanuel Bernard"
    "memberOf_jugId" : "summer_camp"
}
----
====

.Bidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class SalesForce {

    @Id
    private String id;
    private String corporation;

    @OneToMany(mappedBy = "salesForce")
    private Set<SalesGuy> salesGuys = new HashSet<SalesGuy>();

    // getters, setters ...
}

@Entity
public class SalesGuy {
    private String id;
    private String name;

    @ManyToOne
    private SalesForce salesForce;

    // getters, setters ...
}
----

SalesForce collection

[source, JSON]
----
{
    "_id" : "red_hat",
    "corporation" : "Red Hat",
    "salesGuys" : [ "eric", "simon" ]
}
----

SalesGuy collection

[source, JSON]
----
{
    "_id" : "eric",
    "name" : "Eric"
    "salesForce_id" : "red_hat",
}
{
    "_id" : "simon",
    "name" : "Simon",
    "salesForce_id" : "red_hat"
}
----
====

.Bidirectional many-to-one between entities with embedded ids
====
[source, JAVA]
----
@Entity
public class Game {

    @EmbeddedId
    private GameId id;

    private String name;

    @ManyToOne
    private Court playedOn;

    // getters, setters ...
}

public class GameId implements Serializable {

    private String category;

    @Column(name = "id.gameSequenceNo")
    private int sequenceNo;

    // getters, setters ...
    // equals / hashCode
}

@Entity
public class Court {

    @EmbeddedId
    private CourtId id;

    private String name;

    @OneToMany(mappedBy = "playedOn")
    private Set<Game> games = new HashSet<Game>();

    // getters, setters ...
}

public class CourtId implements Serializable {

    private String countryCode;
    private int sequenceNo;

    // getters, setters ...
    // equals / hashCode
}
----

.Court collection
[source, JSON]
----
{
    "_id" : {
        "countryCode" : "DE",
        "sequenceNo" : 123
    },
    "name" : "Hamburg Court",
    "games" : [
        { "gameSequenceNo" : 457, "category" : "primary" },
        { "gameSequenceNo" : 456, "category" : "primary" }
    ]
}
----

.Game collection
[source, JSON]
----
{
    "_id" : {
        "category" : "primary",
        "gameSequenceNo" : 456
    },
    "name" : "The game",
    "playedOn_id" : {
        "countryCode" : "DE",
        "sequenceNo" : 123
    }
}
{
    "_id" : {
        "category" : "primary",
        "gameSequenceNo" : 457
    },
    "name" : "The other game",
    "playedOn_id" : {
        "countryCode" : "DE",
        "sequenceNo" : 123
    }
}
----
====

Here we see that the embedded id is represented as a nested document
and directly referenced by the associations.

[[mongodb-in-entity-to-many-associations]]
===== To-many associations

.Unidirectional one-to-many
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide",
  "products" : [ "Beer", "Pretzel" ]
}
----

Product collection

[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----
====

.Unidirectional one-to-many with @OrderColumn
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide",
  "products" : [
    {
      "products_name" : "Pretzel",
      "products_ORDER" : 1
    },
    {
      "products_name" : "Beer",
      "products_ORDER" : 0
    }
  ]
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----
====

A map can be used to represent an association,
in this case Hibernate OGM will store the key of the map
and the associated id.

.Unidirectional one-to-many using maps with defaults
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    private Map<String, Address> addresses = new HashMap<String, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

User collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "user_001",
  "addresses" : [
    {
      "work" : "address_001",
      "home" : "address_002"
    }
  ]
}
----

Address collection as JSON in MongoDB

[source, JSON]
----
{ "_id" : "address_001", "city" : "Rome" }
{ "_id" : "address_002", "city" : "Paris" }
----
====

If the map value cannot be represented by a single field (e.g. when referencing a type with a composite id
or using an embeddable type as map value type),
a sub-document containing all the required fields will be stored as value.

If the map key either is not of type `String` or it is made up of several columns (composite map key),
the optimized structure shown in the example above cannot be used as MongoDB only allows for Strings as field names.
In that case the association will be represented by a list of sub-documents, also containing the map key column(s).
You can use `@MapKeyColumn` to rename the field containing the key of the map,
otherwise it will default to "<%COLLECTION_ROLE%>_KEY", e.g. "addresses_KEY".

.Unidirectional one-to-many using maps with @MapKeyColumn
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    @MapKeyColumn(name = "addressType")
    private Map<Long, Address> addresses = new HashMap<Long, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

User collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "user_001",
  "addresses" : [
    {
      "addressType" : 1,
      "addresses_id" : "address_001"
    },
    {
      "addressType" : 2,
      "addresses_id" : "address_002"
    }
  ]
}
----

Address collection as JSON in MongoDB

[source, JSON]
----
{ "_id" : "address_001", "city" : "Rome" }
{ "_id" : "address_002", "city" : "Paris" }
----
====

In case you want to enforce the list-style represention also for maps with a single key column of type `String`
(e.g. when reading back data persisted by earlier versions of Hibernate OGM),
you can do so by setting the option `hibernate.ogm.datastore.document.map_storage` to the value `AS_LIST`.

.Unidirectional many-to-many using in entity strategy
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

Student collection

[source, JSON]
----
{
  "_id" : "john",
  "name" :"John Doe" }
{
  "_id" : "mario",
  "name" : "Mario Rossi"
}
{
  "_id" : "kate",
  "name" : "Kate Doe"
}
----

ClassRoom collection

[source, JSON]
----
{
  "_id" : NumberLong(1),
  "lesson" : "Math"
  "students" : [
     "mario",
     "john"
  ]
}
{
  "_id" : NumberLong(2),
  "lesson" : "English"
  "students" : [
     "mario",
     "kate"
  ]
}
----
====

.Bidirectional many-to-many
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany( mappedBy = "bankAccounts" )
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
    "_id" : "owner_1",
    "SSN" : "0123456"
    "bankAccounts" : [ "account_1" ]
}
----

BankAccount collection

[source, JSON]
----
{
    "_id" : "account_1",
    "accountNumber" : "X2345000"
    "owners" : [ "owner_1", "owner2222" ]
}
----
====

.Ordered list with embedded id
====
[source, JAVA]
----
@Entity
public class Race {
    @EmbeddedId
    private RaceId raceId;

    @OrderColumn(name = "ranking")
    @OneToMany @JoinTable(name = "Race_Runners")
    private List<Runner> runnersByArrival = new ArrayList<Runner>();

    // getters, setters ...
}

public class RaceId implements Serializable {
    private int federationSequence;
    private int federationDepartment;

    // getters, setters, equals, hashCode
}

@Entity
public class Runner {
    @EmbeddedId
    private RunnerId runnerId;
    private int age;

    // getters, setters ...
}

public class RunnerId implements Serializable {
    private String firstname;
    private String lastname;

    // getters, setters, equals, hashCode
}
----

.Race collection
[source, JSON]
----
{
    "_id": {
        "federationDepartment": 75,
        "federationSequence": 23
    },
    "runnersByArrival": [{
        "firstname": "Pere",
        "lastname": "Noel",
        "ranking": 1
    }, {
        "firstname": "Emmanuel",
        "lastname": "Bernard",
        "ranking": 0
    }]
}
----

.Runner collection
[source, JSON]
----
{
    "_id": {
        "firstname": "Pere",
        "lastname": "Noel"
    },
    "age": 105
} {
    "_id": {
        "firstname": "Emmanuel",
        "lastname": "Bernard"
    },
    "age": 37
}
----
====

[[mongodb-collection-per-association-strategy]]
===== One collection per association strategy

In this strategy, Hibernate OGM creates a MongoDB collection per association
in which it will store all navigation information for that particular association.

This is the strategy closest to the relational model.
If an entity A is related to B and C, 2 collections will be created.
The name of this collection is made of the association table concatenated with `associations_`.

For example, if the `BankAccount` and `Owner` are related,
the collection used to store will be named `associations_Owner_BankAccount`. You can rename
The prefix is useful to quickly identify the association collections from the entity collections.
You can also decide to rename the collection representing the association using `@JoinTable`
(see <<mongodb-one-collection-strategy-join-table, an example>>)

Each document of an association collection has the following structure:

* `_id` contains the id of the owner of relationship
* `rows` contains all the id of the related entities

[NOTE]
====
The preferred approach is to use the <<mongodb-in-entity-strategy, in-entity strategy>>
but this approach can alleviate the problem of having documents that are too big.
====

.Unidirectional relationship
====
[source, JSON]
----
{
    "_id" : { "owners_id" : "owner0001" },
    "rows" : [
        "accountABC",
        "accountXYZ"
    ]
}
----
====

.Bidirectional relationship
====
[source, JSON]
----
{
    "_id" : { "owners_id" : "owner0001" },
    "rows" : [ "accountABC", "accountXYZ" ]
}
{
    "_id" : { "bankAccounts_id" : "accountXYZ" },
    "rows" : [ "owner0001" ]
}
----
====

[NOTE]
====
This strategy won't affect *-to-one associations or embedded collections.
====

.Unidirectional one-to-many using one collection per strategy
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

associations_Basket_Product collection
[source, JSON]
----
{
  "_id" : { "Basket_id" : "davide_basket" },
  "rows" : [ "Beer", "Pretzel" ]
}
----
====

The order of the element in the list might be preserved using @OrderColumn.
Hibernate OGM will store the order adding an additional fieldd to the document
containing the association.

.Unidirectional one-to-many using one collection per strategy with @OrderColumn
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    @OrderColumn
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection

[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

associations_Basket_Product collection

[source, JSON]
----
{
  "_id" : { "Basket_id" : "davide_basket" },
  "rows" : [
    {
      "products_name" : "Pretzel",
      "products_ORDER" : 1
    },
    {
      "products_name" : "Beer",
      "products_ORDER" : 0
    }
  ]
}
----
====

.Unidirectional many-to-many using one collection per association strategy
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

Student collection

[source, JSON]
----
{
  "_id" : "john",
  "name" : "John Doe"
}
{
  "_id" : "mario",
  "name" : "Mario Rossi"
}
{
  "_id" : "kate",
  "name" : "Kate Doe"
}
----

ClassRoom collection

[source, JSON]
----
{
  "_id" : NumberLong(1),
  "lesson" : "Math"
}
{
  "_id" : NumberLong(2),
  "lesson" : "English"
}
----

associations_ClassRoom_Student

[source, JSON]
----
{
  "_id" : {
    "ClassRoom_id" : NumberLong(1),
  },
  "rows" : [ "john", "mario" ]
}
{
  "_id" : {
    "ClassRoom_id" : NumberLong(2),
  },
  "rows" : [ "mario", "kate" ]
}
----
====

.Bidirectional many-to-many using one collection per association strategy
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany(mappedBy = "bankAccounts")
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
  "_id" : "owner_1",
  "SSN" : "0123456"
}
----

BankAccount collection

[source, JSON]
----
{
  "_id" : "account_1",
  "accountNumber" : "X2345000"
}
----

associations_AccountOwner_BankAccount collection

[source, JSON]
----
{
  "_id" : {
    "bankAccounts_id" : "account_1"
  },
  "rows" : [ "owner_1" ]
}
{
  "_id" : {
    "owners_id" : "owner_1"
  },
  "rows" : [ "account_1" ]
}
----
====

[[mongodb-one-collection-strategy-join-table]]
You can change the name of the collection containing the association using the `@JoinTable` annotation.
In the following example, the name of the collection containing the association is `OwnerBankAccounts`
(instead of the default `associations_AccountOwner_BankAccount`)

.Bidirectional many-to-many using one collection per association strategy and @JoinTable
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    @JoinTable( name = "OwnerBankAccounts" )
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany(mappedBy = "bankAccounts")
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
  "_id" : "owner_1",
  "SSN" : "0123456"
}
----

BankAccount collection

[source, JSON]
----
{
  "_id" : "account_1",
  "accountNumber" : "X2345000"
}
----

OwnerBankAccount

[source, JSON]
----
{
  "_id" : {
    "bankAccounts_id" : "account_1"
  },
  "rows" : [ "owner_1" ]
}
{
  "_id" : {
    "owners_id" : "owner_1"
  },
  "rows" : [ "account_1" ]
}
----
====

[[mongodb-association-document-strategy]]
===== Global collection strategy

With this strategy, Hibernate OGM creates a single collection named `Associations`
in which it will store all navigation information for all associations.
Each document of this collection is structured in 2 parts.
The first is the `_id` field which contains the identifier information
of the association owner and the name of the association table.
The second part is the `rows` field which stores (into an embedded collection) all ids
that the current instance is related to.

[NOTE]
====
This strategy won't affect *-to-one associations or embedded collections.

Generally, you should not make use of this strategy
unless embedding the association information proves to be too big for your document
and you wish to separate them.
====

.Associations collection containing unidirectional association
====
[source, JSON]
----
{
    "_id": {
        "owners_id": "owner0001",
        "table": "AccountOwner_BankAccount"
    },
    "rows": [ "accountABC", "accountXYZ" ]
}
----
====

For a bidirectional relationship, another document is created where ids are reversed.
Don't worry, Hibernate OGM takes care of keeping them in sync:

.Associations collection containing a bidirectional association
====
[source, JSON]
----
{
    "_id": {
        "owners_id": "owner0001",
        "table": "AccountOwner_BankAccount"
    },
    "rows": [ "accountABC", "accountXYZ" ]
}
{
    "_id": {
        "bankAccounts_id": "accountXYZ",
        "table": "AccountOwner_BankAccount"
    },
    "rows": [ "owner0001" ]
}
----
====

.Unidirectional one-to-many using global collection strategy
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

Associations collection
[source, JSON]
----
{
  "_id" : {
    "Basket_id" : "davide_basket",
    "table" : "Basket_Product"
  },
  "rows" : [
    {
      "products_name" : "Pretzel",
      "products_ORDER" : 1
    },
    {
      "products_name" : "Beer",
    "products_ORDER" : 0
    }
  ]
}
----
====

.Unidirectional one-to-many using global collection strategy with `@JoinTable`
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    // It will change the value stored in the field table in the Associations collection
    @JoinTable( name = "BasketContent" )
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

Associations collection

[source, JSON]
----
{
  "_id" : {
    "Basket_id" : "davide_basket",
    "table" : "BasketContent"
  },
  "rows" : [ "Beer", "Pretzel" ]
}
----
====

.Unidirectional many-to-many using global collection strategy
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

Student collection

[source, JSON]
----
{
  "_id" : "john",
  "name" : "John Doe"
}
{
  "_id" : "mario",
  "name" : "Mario Rossi"
}
{
  "_id" : "kate",
  "name" : "Kate Doe"
}
----

ClassRoom collection

[source, JSON]
----
{
  "_id" : NumberLong(1),
  "lesson" : "Math"
}
{
  "_id" : NumberLong(2),
  "lesson" : "English"
}
----

Associations collection

[source, JSON]
----
{
  "_id" : {
    "ClassRoom_id" : NumberLong(1),
    "table" : "ClassRoom_Student"
  },
  "rows" : [ "john", "mario" ]
}
{
  "_id" : {
    "ClassRoom_id" : NumberLong(2),
    "table" : "ClassRoom_Student"
  },
  "rows" : [ "mario", "kate" ]
}
----
====

.Bidirectional many-to-many using global collection strategy
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany(mappedBy = "bankAccounts")
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
  "_id" : "owner0001",
  "SSN" : "0123456"
}
----

BankAccount collection

[source, JSON]
----
{
  "_id" : "account_1",
  "accountNumber" : "X2345000"
}
----

Associations collection

[source, JSON]
----
{
  "_id" : {
    "bankAccounts_id" : "account_1",
    "table" : "AccountOwner_BankAccount"
    },

  "rows" : [ "owner0001" ]
}
{
  "_id" : {
    "owners_id" : "owner0001",
    "table" : "AccountOwner_BankAccount"
  },

  "rows" : [ "account_1" ]
}
----
====

[[ogm-mongodb-indexes-unique-constraints]]
=== Indexes and unique constraints

==== Standard indexes and unique constraints

You can create your index and unique constraints in MongoDB using the standard JPA annotations.

.Creating indexes and unique constraints using JPA annotations
====
[source, JAVA]
----
@Entity
@Table(indexes = {
    @Index(columnList = "author, name", name = "author_name_idx", unique = true),
    @Index(columnList = "name DESC", name = "name_desc_idx")
})
public class Poem {

    @Id
    private String id;
    private String name;
    private String author;

    @Column(unique = true)
    private String url;

   // getters, setters ...
}
----
====

[NOTE]
====
MongoDB supports unique constraints via unique indexes. It considers `null` as a value to be unique: you can only
have one `null` value per unique index. This is not what is commonly accepted as the definition of a unique constraint in
the JPA world. Thus, by default, we create the unique indexes as `sparse`: it only indexes defined values so that the
unique constraints accept multiple `null` values.
====

==== Using MongoDB specific index options

MongoDB supports https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/[a number of options for
index creation].

It is possible to define them using the `@IndexOption` annotation.

.Creating indexes with MongoDB specific options
====
[source, JAVA]
----
@Entity
@Table(indexes = {
    @Index(columnList = "author", name = "author_idx")
})
@IndexOptions(
    @IndexOption(forIndex = "author_idx", options = "{ background : true, sparse : true, partialFilterExpression : { author: 'Verlaine' } }")
)
public class Poem {

    @Id
    private String id;
    private String name;
    private String author;

   // getters, setters ...
}
----
====

`@IndexOption` simply passes the options to MongoDB at index creation: you can use every option available in MongoDB.

==== Full text indexes

MongoDB supports the ability to create one (and only one) full text index per collection.

As JPA does not support the ability to define `text` as an order in the `@Index` annotation (only `ASC` and `DESC`
are supported), this ability has been included inside the `@IndexOption` mechanism. You simply need to add `text: true`
to the options passed to MongoDB, Hibernate OGM interprets it and translates the index to a full text index.

.Creating a full text index
====
[source, JAVA]
----
@Entity
@Table(indexes = {
    @Index(columnList = "author, name", name = "author_name_text_idx")
})
@IndexOptions(
    @IndexOption(forIndex = "author_name_text_idx", options = "{ text: true, default_language : 'fr', weights : { author: 2, name: 5 } }")
)
public class Poem {

    @Id
    private String id;
    private String name;
    private String author;

   // getters, setters ...
}
----
====

=== Transactions

MongoDB does not support transactions.
Only changes applied to the same document are done atomically.
A change applied to more than one document will not be applied atomically.
This problem is slightly mitigated by the fact that Hibernate OGM queues all changes
before applying them during flush time.
So the window of time used to write to MongoDB is smaller than what you would have done manually.

We recommend that you still use transaction demarcations with Hibernate OGM
to trigger the flush operation transparently (on commit).
But do not consider rollback as a possibility, this won't work.

[[ogm-mongodb-optimisticlocking]]
=== Optimistic Locking

MongoDB does not provide a built-in mechanism for detecting concurrent updates to the same document
but it provides a way to execute atomic find and update operations.
By exploiting this commands Hibernate OGM can detect concurrent modifications to the same document.

You can enable optimistic locking detection using the annotation `@Version`:

.Optimistic locking detection via `@Version`
====
[source, JAVA]
----
@Entity
public class Planet implements Nameable {

    @Id
    private String id;
    private String name;

    @Version
    private int version;

   // getters, setters ...
}
----

----
{
  "_id" : "planet-1",
  "name" : "Pluto",
  "version" : 0
}
----
====

The `@Version` annotation define which attribute will keep track of the version of the document,
Hibernate OGM will update the field when required and if two changes from two different sessions (for example)
are applied to the same document a `org.hibernate.StaleObjectStateException` is thrown.

You can use `@Column` to change the name of the field created on MongoDB:

.Optimistic locking detection via `@Version` using `@Column`
====
[source, JAVA]
----
@Entity
public class Planet implements Nameable {

    @Id
    private String id;
    private String name;

    @Version
    @Column(name="OPTLOCK")
    private int version;

   // getters, setters ...
}
----

----
{
  "_id" : "planet-1",
  "name" : "Pluto",
  "OPTLOCK" : 0
}
----
====

[[ogm-mongodb-queries]]
=== Queries

You can express queries in a few different ways:

* using JPQL
* using a native MongoQL query
* using a Hibernate Search query (brings advanced full-text and geospatial queries)

While you can use JPQL for simple queries, you might hit limitations.
The current recommended approach is to use native MongoQL
if your query involves nested (list of) elements.

MongoDB doesn't require Hibernate Search to run queries.

[NOTE]
====
In order to reflect changes performed in the current session,
all entities affected by a given query are flushed to the datastore prior to query execution
(that's the case for Hibernate ORM as well as Hibernate OGM).

For not fully transactional stores such as MongoDB
this can cause changes to be written as a side-effect of running queries
which cannot be reverted by a possible later rollback.

Depending on your specific use cases and requirements you may prefer to disable auto-flushing,
e.g. by invoking `query.setFlushMode( FlushMode.MANUAL )`.
Bear in mind though that query results will then not reflect changes applied within the current session.
====

==== JPQL queries

Hibernate OGM is a work in progress, so only a sub-set of JPQL constructs is available
when using the JPQL query support. This includes:

* simple comparisons using "<", "+<=+", "=", ">=" and ">"
* `IS NULL` and `IS NOT NULL`
* the boolean operators `AND`, `OR`, `NOT`
* `LIKE`, `IN` and `BETWEEN`
* `ORDER BY`
* inner `JOIN` on embedded collections
* projections of regular and embedded properties

Queries using these constructs will be transformed into equivalent native MongoDB queries.

[NOTE]
====
Let us know <<ogm-howtocontribute,by opening an issue or sending an email>>
what query you wish to execute.
Expanding our support in this area is high on our priority list.
====

[[ogm-mongodb-queries-native]]
==== Native MongoDB queries

Hibernate OGM also supports certain forms of native queries for MongoDB.
Currently two forms of native queries are available via the MongoDB backend:

* find queries specifying the search criteria only
* queries specified using the MongoDB CLI syntax (<<ogm-mongodb-cli-syntax>>)

The former always maps results to entity types.
The latter either maps results to entity types or to certain supported forms of projection.
Note that parameterized queries are not supported by MongoDB, so don't expect `Query#setParameter()` to work.

You can execute native queries as shown in the following example:

.Using the JPA API
====
[source, JAVA]
----
@Entity
public class Poem {

    @Id
    private Long id;

    private String name;

    private String author;

   // getters, setters ...
}

...

javax.persistence.EntityManager em = ...

// criteria-only find syntax
String query1 = "{ $and: [ { name : 'Portia' }, { author : 'Oscar Wilde' } ] }";
Poem poem = (Poem) em.createNativeQuery( query1, Poem.class ).getSingleResult();

// criteria-only find syntax with order-by
String query2 = "{ $query : { author : 'Oscar Wilde' }, $orderby : { name : 1 } }";
List<Poem> poems = em.createNativeQuery( query2, Poem.class ).getResultList();

// projection via CLI-syntax
String query3 = "db.WILDE_POEM.find(" +
    "{ '$query' : { 'name' : 'Athanasia' }, '$orderby' : { 'name' : 1 } }" +
    "{ 'name' : 1 }" +
    ")";

// will contain name and id as MongoDB always returns the id for projections
List<Object[]> poemNames = (List<Object[]>)em.createNativeQuery( query3 ).getResultList();

// projection via CLI-syntax
String query4 = "db.WILDE_POEM.count({ 'name' : 'Athanasia' })";

Object[] count = (Object[])em.createNativeQuery( query4 ).getSingleResult();
----
====

The result of a query is a managed entity (or a list thereof) or a projection of attributes in form of an object array,
just like you would get from a JPQL query.

.Using the Hibernate native API
====
[source, JAVA]
----
OgmSession session = ...

String query1 = "{ $and: [ { name : 'Portia' }, { author : 'Oscar Wilde' } ] }";
Poem poem = session.createNativeQuery( query1 )
                      .addEntity( "Poem", Poem.class )
                      .uniqueResult();

String query2 = "{ $query : { author : 'Oscar Wilde' }, $orderby : { name : 1 } }";
List<Poem> poems = session.createNativeQuery( query2 )
                      .addEntity( "Poem", Poem.class )
                      .list();
----
====

Native queries can also be created using the `@NamedNativeQuery` annotation:

.Using @NamedNativeQuery
====
[source, JAVA]
----
@Entity
@NamedNativeQuery(
   name = "AthanasiaPoem",
   query = "{ $and: [ { name : 'Athanasia' }, { author : 'Oscar Wilde' } ] }",
   resultClass = Poem.class )
public class Poem { ... }

...

// Using the EntityManager
Poem poem1 = (Poem) em.createNamedQuery( "AthanasiaPoem" )
                     .getSingleResult();

// Using the Session
Poem poem2 = (Poem) session.getNamedQuery( "AthanasiaPoem" )
                     .uniqueResult();
----
====

Hibernate OGM stores data in a natural way so you can still execute queries using the
MongoDB driver, the main drawback is that the results are going to be raw MongoDB
documents and not managed entities.

[[ogm-mongodb-cli-syntax]]

===== CLI Syntax

Hibernate OGM can execute native queries expressed using the MongoDB CLI syntax with some limitations.
Currently `find()`, `findOne()`, `findAndModify()`, and `count()` queries are supported. Furthermore, three
types of write queries are supported via the CLI syntax: `insert()`, `remove()`, and `update()`. Other query
types may be supported in future versions.

As one would expect, `find()`, `findOne()`, `findAndModify()`, `aggregate`,
`distinct()`, and `count()` can be executed using
`javax.persistence.Query.getSingleResult()` or `javax.persistence.Query.getResultList()`, while `insert()`,
`remove()`, and `update()` require using `javax.persistence.Query.executeUpdate()`. Also note that,
`javax.persistence.Query.executeUpdate()` may return `-1` in case execution of a query was not acknowledged
relative to the write concern used.
Via `javax.persistence.Query.executeUpdate()` it is also possible to run `db.Collection.drop()`
queries.

[NOTE]
====
`db.Collection.drop()` will always return 1. This is because the underlying driver we are
using doesn't return any value after the execution of the operation.
====

The following functions can be used in the provided JSON:
`BinData`, `Date`, `HexData`, `ISODate`, `NumberLong`, `ObjectId`, `Timestamp`,
`RegExp`, `DBPointer`, `UUID`, `GUID`, `CSUUID`, `CSGUID`, `JUUID`, `JGUID`, `PYUUID`, `PYGUID`.

[NOTE]
====
`NumberInt` is not supported as it is currently not supported by the MongoDB Java driver.
====

No cursor operations such as `sort()` are supported.
Instead use the corresponding MongoDB http://docs.mongodb.org/manual/reference/operator/query-modifier/[query modifiers]
such as `$orderby` within the criteria parameter.

You can limit the results of a query using the `setMaxResults(...)` method.

JSON parameters passed via the CLI syntax must be specified using the
http://docs.mongodb.org/manual/reference/mongodb-extended-json/[strict mode].
Specifically, keys need to be given within quotes; the only relaxation of this is that single quotes
may be used when specifying attribute names/values to facilitate embedding queries within
Java strings.

Note that results of projections are returned as retrieved from the MongoDB driver at the moment and
are not (yet) converted using suitable Hibernate OGM type implementations.
This requirement is tracked under https://hibernate.atlassian.net/browse/OGM-1031[OGM-1031].

.CLI syntax examples
====
[source, JAVA]
----

// Valid syntax
String valid = "db.Poem.find({ \"name\" : \"Athanasia\" })";

String alsoValid = "db.Poem.find({ '$or' : [{'name': 'Athanasia' }, {'name': 'Portia' }]})";

String validAggregation = "db.Poem.aggregate([{ '$match': {'author': { '$regex': 'oscar.*', '$options': 'i' } } }, { '$sort': {'name': -1 } } ])";

// NOT Valid syntax, it will throw an exception: com.mongodb.util.JSONParseException
String notValid =  "db.Poem.find({ name : \"Athanasia\" })";

String alsoNotValid = "db.Poem.find({ $or : [{name: 'Athanasia' }, {name: 'Portia' }]})";

----
====

.CLI syntax sort and limit results alternatives
====
[source, JAVA]
----
String nativeQuery = "db.Poem.find({ '$query': { 'author': 'Oscar Wilde' }, '$orderby' : { 'name' : 1 } })";

// Using hibernate session
List<Poem> result = session.createNativeQuery( nativeQuery )
	.addEntity( Poem.class )
	.setMaxResults( 2 )
	.list();

// Using JPA entity manager
List<Poem> results = em.createNativeQuery( nativeQuery, Poem.class )
	.setMaxResults( 2 )
	.getResultList();
----
====

.CLI syntax update examples
====
[source, JAVA]
----
String updateQuery = "db.Poem.findAndModify({ 'query': {'_id': 1}, 'update': { '$set': { 'author': 'Oscar Wilde' } }, 'new': true })";
List<Poem> updated = session.createNativeQuery( updateQuery ).addEntity( Poem.class ).list();

String insertQuery = "db.Poem.insert({ '_id': { '$numberLong': '11' }, 'author': 'Oscar Wilder', 'name': 'The one and wildest', 'rating': '1' } )";
int inserted = session.createNativeQuery( insertQuery ).executeUpdate();

String removeQuery = "db.Poem.remove({ '_id': { '$numberLong': '11' } })";
int removed = session.createNativeQuery( removeQuery ).executeUpdate();
----
====

[WARNING]
====
Support for the `$regexp` operator is limited to the string syntax. We do not support the `/pattern/` syntax as it is not
currently supported by the MongoDB Java driver.

[source, JAVA]
----
// Valid syntax
String nativeQuery = "{ $query : { author : { $regex : '^Oscar' } }, $orderby : { name : 1 } }";
List<Poem> result = session.createNativeQuery( nativeQuery ).addEntity( Poem.class ).list();
----
====

[[ogm-mongodb-stored-proc-native]]

==== Server-side JavaScript and stored procedures

[NOTE]
====
This is an experimental feature.
====

In MongoDB, it is possible to call server-side JavaScript as if it is a stored procedure.
You can use the existing methods in JPA:

.Calling server-side JavaScript with positional parameters
====
[source, JAVA]
----
  @Entity
  public class Car {
    @Id
    private Integer id;

    private String brand;

    ...
  }

  EntityManager em = ...
  StoredProcedureQuery storedProcedureQuery = em.createStoredProcedureQuery( "findMostExpensiveCars", Car.class );
  storedProcedureQuery.registerStoredProcedureParameter( "year", Integer.class, ParameterMode.IN );
  storedProcedureQuery.setParameter( "year", 1995 );
  List<Car> cars = storedProcedureQuery.getResultList();
----
====

This example will work assuming that there is a `findMostExpensiveCars` JavaScript function in MongoDB
and that the result of the function is a list of cars that can be mapped to the `Car` entity.

.Calling server-side JavaScript with Hibernate OGM with positional parameters
====
[source, JSON]
----
{
  "result" : [
    { "id":1, "brand":"Bentley" },
    { "id":2, "brand":"Maserati" },
  ]
}
----
====

More details about server-side functions can be found in
https://docs.mongodb.com/manual/core/server-side-JavaScript[the MongoDB reference documentation].

==== Hibernate Search

You can index your entities using Hibernate Search.
That way, a set of secondary indexes independent of MongoDB is maintained by Hibernate Search
and you can run Lucene queries on top of them.
The benefit of this approach is a nice integration at the JPA / Hibernate API level
(managed entities are returned by the queries).
The drawback is that you need to store the Lucene indexes somewhere
(file system, infinispan grid, etc).
Have a look at the Infinispan section (<<ogm-infinispan-indexstorage>>)
for more info on how to use Hibernate Search.

=== Geospatial support

==== Geospatial fields

Our MongoDB integration supports the ability to declare geospatial fields by using specific Java types that will be
automatically converted to GeoJSON objects stored in MongoDB.

We currently support the following types:

 * `GeoPoint`, stored as a GeoJSON Point
 * `GeoMultiPoint`, stored as a GeoJSON MultiPoint
 * `GeoLineString`, stored as a GeoJSON LineString
 * `GeoMultiLineString`, stored as a GeoJSON MultiLineString
 * `GeoPolygon`, stored as a GeoJSON Polygon
 * `GeoMultiPolygon`, stored as a GeoJSON MultiPolygon

You can find more information about these types and their constraints in the
https://docs.mongodb.com/manual/reference/geojson/[MongoDB documentation].

.Declaring a geospatial field
====
[source, JAVA]
----
@Entity
public class Restaurant {

    // [...]

    private GeoPoint location;
}
----
====

These Java types come with handy constructors and helpers to help manipulate them.

.Instantiating a polygon
====
[source, JAVA]
----
GeoPolygon polygon = new GeoPolygon(
        new GeoPoint( 4.814922, 45.7753612 ),
        new GeoPoint( 4.8160825, 45.7327172 ),
        new GeoPoint( 4.9281299, 45.7211302 ),
        new GeoPoint( 4.8706127, 45.786724 ),
        new GeoPoint( 4.814922, 45.7753612 )
);
----
====

==== Geospatial indexes and queries

To be able to run optimized queries on geospatial fields, you need to declare spatial indexes.

You can leverage your usual annotations to declare the indexes directly on your entities.

.Declaring a geospatial index
====
[source, JAVA]
----
@Entity
@Table(indexes = {
		@Index(columnList = "location", name = "location_spatial_idx")
})
@IndexOptions(
		@IndexOption(forIndex = "location_spatial_idx", options = "{ _type: '2dsphere' }")
)
public class Restaurant {

    // [...]

    private GeoPoint location;
}
----
====

Note that you need to precise the type of the index using an `@IndexOption` annotation.

The next step is to execute a geospatial query using a native query.

.Finding entities around a point
====
[source, JAVA]
----
GeoPoint geoPoint = new GeoPoint( 4.8520035, 45.7498209 );

Query query = session
        .createNativeQuery( "{ location: { $near: { $geometry: " + geoPoint.toBsonDocument() + ", $maxDistance: 500 } } }" )
        .addEntity( Restaurant.class );
List<Restaurant> result = query.list();
----
====

.Finding entities within a polygon
====
[source, JAVA]
----
GeoPolygon geoPolygon = new GeoPolygon(
        new GeoPoint( 4.814922, 45.7753612 ),
        new GeoPoint( 4.8160825, 45.7327172 ),
        new GeoPoint( 4.9281299, 45.7211302 ),
        new GeoPoint( 4.8706127, 45.786724 ),
        new GeoPoint( 4.814922, 45.7753612 )
);

Query query = session
        .createNativeQuery( "{ location: { $geoWithin: { $geometry: " + geoPolygon.toBsonDocument() + " } } }" )
        .addEntity( Restaurant.class );
List<Restaurant> result = query.list();
----
====

To learn more about MongoDB spatial indexes and queries, please refer to the
https://docs.mongodb.com/manual/geospatial-queries/[MongoDB documentation].

[[ogm-mongodb]]

== MongoDB

http://www.mongodb.org[MongoDB] is a document oriented datastore
written in C++ with strong emphasis on ease of use.
The nested nature of documents make it a particularly natural fit for most object representations.

This implementation is based upon the MongoDB Java driver.
The currently supported version is {mongodb-version}.

=== Why should I use Hibernate OGM with MongoDB

It is possible that in your project you have some entities that might benefit from MongoDB
dynamic schema, but having a schema makes it possible to obtain better performance because
the datastore can use the information of the schema to apply some optimizations that
wouldn't be otherwise possible.

JPA already has ways to define constraints and indexes and via Hibernate OGM you can
use the same annotations for both your relational and not relational needs.

Hibernate OGM cannot make MongoDB transactional but by using the JPA transaction demarcation
mechanism it can group the operations and flush them to the datastore to
minimize the number of requests.

Another benefit of using Hibernate OGM with MongoDB is that it will also make it possible
to use Hibernate Search out of the box. Hibernate Search brings the power of Lucene
to your project, giving you the ability to run fast google-like searches.

This means that you can query the datastore using:

* JPQL queries (see <<ogm-jpql-query>>)
* MongoDB native queries (see <<ogm-mongodb-queries-native>>)
* Full-text queries (see <<ogm-query-using-hibernate-search>>)

One of Hibernate OGM main goal is to map entities in a "natural" way, this means that your
datastore will still be accessible in case you need to use other tools or want to run
native queries occasionally.

=== Configuring MongoDB

Configuring Hibernate OGM to use MongoDb is easy:

* Add the MongoDB module and driver to the classpath
* provide the MongoDB URL to Hibernate OGM

==== Adding MongoDB dependencies

To add the dependencies via Maven, add the following module:

[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-mongodb</artifactId>
    <version>{hibernate-ogm-version}</version>
</dependency>
----

This will pull the MongoDB driver transparently.

If you're not using a dependency management tool,
copy all the dependencies from the distribution in the directories:

* `/lib/required`
* `/lib/mongodb`
* Optionally - depending on your container - you might need some of the jars from `/lib/provided`

MongoDB does not require Hibernate Search for the execution of JPQL or HQL queries.

==== MongoDB specific configuration properties

To get started quickly, pay attention to the following options:

* `hibernate.ogm.datastore.provider`
* `hibernate.ogm.datastore.host`
* `hibernate.ogm.datastore.database`

And we should have you running.
The following properties are available to configure MongoDB support:

.MongoDB datastore configuration properties
hibernate.ogm.datastore.provider::
To use MongoDB as a datastore provider, this property must be set to `mongodb`
hibernate.ogm.option.configurator::
The fully-qualified class name or an instance of a programmatic option configurator (see <<ogm-mongodb-programmatic-configuration>>)
hibernate.ogm.datastore.host::
The hostname and port of the MongoDB instance.
The optional port is concatenated to the host and separated by a colon.
When using replica sets, you can define the various servers in a comma separated list of hosts and ports.
Let's see a few valid examples:

* `mongodb.example.com`
* `mongodb.example.com:27018`
* `2001:db8::ff00:42:8329` (IPv6)

* `[2001:db8::ff00:42:8329]:27018` (IPv6 with port requires the IPv6 to be surrounded by square brackets)
* `www.example.com, www2.example.com:123, 192.0.2.1, 192.0.2.2:123, 2001:db8::ff00:42:8329, [2001:db8::ff00:42:8329]:123` (replica set)
+
The default value is `127.0.0.1:27017`. If left undefined, the default port is `27017`.
hibernate.ogm.datastore.port::
Deprecated: use `hibernate.ogm.datastore.host`.
The port used by the MongoDB instance.
Ignored when multiple hosts are defined.
The default value is `27017`.
hibernate.ogm.datastore.database::
The database to connect to. This property has no default value.
hibernate.ogm.datastore.create_database::
If set to true, the database will be created if it doesn't exist.
This property default value is false.
hibernate.ogm.datastore.username::
The username used when connecting to the MongoDB server.
This property has no default value.
hibernate.ogm.datastore.password::
The password used to connect to the MongoDB server.
This property has no default value.
This property is ignored if the username isn't specified.
hibernate.ogm.error_handler::
The fully-qualified class name, class object or an instance of `ErrorHandler` to get notified upon errors during flushes (see <<ogm-api-error-handler>>)
hibernate.ogm.mongodb.driver.*::
Defines a prefix for all options which should be passed through to the MongoDB driver.
For available options refer to the JavaDocs of link:http://api.mongodb.org/java/3.0/com/mongodb/MongoClientOptions.Builder.html[MongoClientOptions.Builder]. All `String`, `int` and `boolean` properties
can be set, eg `hibernate.ogm.mongodb.driver.serverSelectionTimeout`.
hibernate.ogm.mongodb.authentication_database::
Defines the name of the authentication database, default value is _admin_.
hibernate.ogm.mongodb.authentication_mechanism::
Defines the authentication mechanism to use. Possible values are:

* `BEST`: Handshakes with the server to find the best authentication mechanism.
* `SCRAM_SHA_1`: The SCRAM SHA 1 Challenge Response mechanism as described in this link:http://tools.ietf.org/html/rfc5802[RFC].
* `MONGODB_CR`: The MongoDB Challenge Response mechanism (deprecated since MongoDB 3)
* `GSSAPI`: The GSSAPI mechanism. See the http://tools.ietf.org/html/rfc4752[RFC]
* `MONGODB_X509`: The MongoDB X.509
* `PLAIN`: The PLAIN mechanism.  See the http://www.ietf.org/rfc/rfc4616.txt[RFC]
hibernate.ogm.datastore.document.association_storage::
Defines the way OGM stores association information in MongoDB.
The following two strategies exist (values of the `org.hibernate.ogm.datastore.document.options.AssociationStorageType` enum):

* `IN_ENTITY`: store association information within the entity
* `ASSOCIATION_DOCUMENT`: store association information in a dedicated document per association

+
`IN_ENTITY` is the default and recommended option
unless the association navigation data is much bigger than the core of the document and leads to performance degradation.
hibernate.ogm.mongodb.association_document_storage::
Defines how to store assocation documents (applies only if the `ASSOCIATION_DOCUMENT`
association storage strategy is used).
Possible strategies are (values of the `org.hibernate.ogm.datastore.mongodb.options.AssociationDocumentStorageType` enum):

* `GLOBAL_COLLECTION` (default): stores the association information in a unique MongoDB collection for all associations
* `COLLECTION_PER_ASSOCIATION` stores the association in a dedicated MongoDB collection per association

hibernate.ogm.datastore.document.map_storage::
Defines the way OGM stores the contents of map-typed associations in MongoDB.
The following two strategies exist (values of the `org.hibernate.ogm.datastore.document.options.MapStorageType` enum):

* `BY_KEY`: map-typed associations with a single key column which is of type `String` will be stored as a sub-document,
organized by the given key; Not applicable for other types of key columns, in which case always `AS_LIST` will be used
* `AS_LIST`: map-typed associations will be stored as an array containing a sub-document for each map entry.
All key and value columns will be contained within the array elements

hibernate.ogm.mongodb.write_concern::
Defines the write concern setting to be applied when issuing writes against the MongoDB datastore.
Possible settings are (values of the `WriteConcernType` enum):
`ACKNOWLEDGED`, `UNACKNOWLEDGED`, `FSYNCED`, `JOURNALED`, `REPLICA_ACKNOWLEDGED`, `MAJORITY` and `CUSTOM`.
When set to `CUSTOM`, a custom `WriteConcern` implementation type has to be specified.
+
This option is case insensitive and the default value is `ACKNOWLEDGED`.
hibernate.ogm.mongodb.write_concern_type::
Specifies a custom `WriteConcern` implementation type (fully-qualified name, class object or instance).
This is useful in cases where the pre-defined configurations are not sufficient,
e.g. if you want to ensure that writes are propagated to a specific number of replicas or given "tag set".
Only takes effect if `hibernate.ogm.mongodb.write_concern` is set to `CUSTOM`.
hibernate.ogm.mongodb.read_preference::
Specifies the `ReadPreference` to be applied when issuing reads against the MongoDB datastore.
Possible settings are (values of the `ReadPreferenceType` enum):
`PRIMARY`, `PRIMARY_PREFERRED`, `SECONDARY`, `SECONDARY_PREFERRED` and `NEAREST`.
It's currently not possible to plug in custom read preference types.
If you're interested in such a feature, please let us know.

For more information, please refer to the
http://api.mongodb.org/java/current/com/mongodb/WriteConcern.html[official documentation].

[NOTE]
====
When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via `org.hibernate.ogm.datastore.mongodb.MongoDBProperties`
when specifying the configuration properties listed above.

Common properties shared between stores are declared on `OgmProperties`
(a super interface of `MongoDBProperties`).

For maximum portability between stores, use the most generic interface possible.
====

[[ogm-mongodb-annotation-configuration]]
==== Annotation based configuration

Hibernate OGM allows to configure store-specific options via Java annotations.
You can override global configurations for a specific entity or even a specify property
by virtue of the location where you place that annotation.

When working with the MongoDB backend, you can specify the following settings:

* the write concern for entities and associations using the `@WriteConcern` annotation
* the read preference for entities and associations using the `@ReadPreference` annotation
* a strategy for storing associations using the `@AssociationStorage` and `@AssociationDocumentStorage` annotations
* a strategy for storing the contents of map-typed associations using the `@MapStorage` annotation

Refer to <<mongodb-associations> to learn more about the options related to storing associations.

The following shows an example:

.Configuring the association storage strategy using annotations
====
[source, JAVA]
----
@Entity
@WriteConcern(WriteConcernType.JOURNALED)
@ReadPreference(ReadPreferenceType.PRIMARY_PREFERRED)
@AssociationStorage(AssociationStorageType.ASSOCIATION_DOCUMENT)
@AssociationDocumentStorage(AssociationDocumentStorageType.COLLECTION_PER_ASSOCIATION)
@MapStorage(MapStorageType.AS_LIST)
public class Zoo {

    @OneToMany
    private Set<Animal> animals;

    @OneToMany
    private Set<Person> employees;

    @OneToMany
    @AssociationStorage(AssociationStorageType.IN_ENTITY)
    private Set<Person> visitors;

    // getters, setters ...
}
----
====

The `@WriteConcern` annotation on the entity level expresses that all writes should be done using the `JOURNALED` setting.
Similarly, the `@ReadPreference` annotation advices the engine to preferably read that entity from the primary node if possible.
The other two annotations on the type-level specify that all associations of the `Zoo`
class should be stored in separate assocation documents, using a dedicated collection per association.
This setting applies to the `animals` and `employees` associations.
Only the elements of the `visitors` association will be stored in the document of the corresponding `Zoo` entity
as per the configuration of that specific property which takes precedence over the entity-level configuration.

[[ogm-mongodb-programmatic-configuration]]
==== Programmatic configuration

In addition to the annotation mechanism,
Hibernate OGM also provides a programmatic API for applying store-specific configuration options.
This can be useful if you can't modify certain entity types or
don't want to add store-specific configuration annotations to them.
The API allows set options in a type-safe fashion on the global, entity and property levels.

When working with MongoDB, you can currently configure the following options using the API:

* write concern
* read preference
* association storage strategy
* association document storage strategy
* strategy for storing the contents of map-typed associations

To set these options via the API, you need to create an `OptionConfigurator` implementation
as shown in the following example:

.Example of an option configurator
====
[source, JAVA]
----
public class MyOptionConfigurator extends OptionConfigurator {

    @Override
    public void configure(Configurable configurable) {
        configurable.configureOptionsFor( MongoDB.class )
            .writeConcern( WriteConcernType.REPLICA_ACKNOWLEDGED )
            .readPreference( ReadPreferenceType.NEAREST )
            .entity( Zoo.class )
                .associationStorage( AssociationStorageType.ASSOCIATION_DOCUMENT )
                .associationDocumentStorage( AssociationDocumentStorageType.COLLECTION_PER_ASSOCIATION )
                .mapStorage( MapStorageType.ASLIST )
                .property( "animals", ElementType.FIELD )
                    .associationStorage( AssociationStorageType.IN_ENTITY )
            .entity( Animal.class )
                .writeConcern( new RequiringReplicaCountOf( 3 ) )
                .associationStorage( AssociationStorageType.ASSOCIATION_DOCUMENT );
    }
}
----
====

The call to `configureOptionsFor()`, passing the store-specific identifier type `MongoDB`,
provides the entry point into the API. Following the fluent API pattern, you then can configure
global options (`writeConcern()`, `readPreference()`) and navigate to single entities or properties to apply options
specific to these (`associationStorage()` etc.).
The call to `writeConcern()`  for the `Animal`  entity shows how a specific write concern type can be used.
Here `RequiringReplicaCountOf` is a custom implementation of `WriteConcern` which ensures
that writes are propagated to a given number of replicas before a write is acknowledged.

Options given on the property level precede entity-level options. So e.g. the `animals` association of the `Zoo`
class would be stored using the in entity strategy, while all other associations of the `Zoo` entity would
be stored using separate association documents.

Similarly, entity-level options take precedence over options given on the global level.
Global-level options specified via the API complement the settings given via configuration properties.
In case a setting is given via a configuration property and the API at the same time,
the latter takes precedence.

Note that for a given level (property, entity, global),
an option set via annotations is overridden by the same option set programmatically.
This allows you to change settings in a more flexible way if required.

To register an option configurator, specify its class name using the `hibernate.ogm.option.configurator` property.
When bootstrapping a session factory or entity manager factory programmatically,
you also can pass in an `OptionConfigurator` instance or the class object representing the configurator type.

[[ogm-mongodb-storage-principles]]
=== Storage principles

Hibernate OGM tries to make the mapping to the underlying datastore as natural as possible
so that third party applications not using Hibernate OGM can still read
and update the same datastore.
We worked particularly hard on the MongoDB model
to offer various classic mappings between your object model
and the MongoDB documents.

To describe things simply, each entity is stored as a MongoDB document.
This document is stored in a MongoDB collection named after the entity type.
The navigational information for each association from one entity to (a set of) entity
is stored in the document representing the entity we are departing from.

[[mongodb-built-in-types]]
==== Properties and built-in types

Each entity is represented by a document.
Each property or more precisely column is represented by a field in this document,
the field name being the column name.

Hibernate OGM supports by default the following property types:

* `java.lang.String`

[source, JSON]
----
  { "text" : "Hello world!" }
----

* `java.lang.Character` (or char primitive)

[source, JSON]
----
  { "delimiter" : "/" }
----

* `java.lang.Boolean` (or boolean primitive)

[source, JSON]
----
  { "favorite" : true } # default mapping
  { "favorite" : "T" } # if @Type(type = "true_false") is given
  { "favorite" : "Y" } # if @Type(type = "yes_no") is given
  { "favorite" : 1 } # if @Type(type = "numeric_boolean") is given
----

* `java.lang.Byte` (or byte primitive)

[source, JSON]
----
  { "display_mask" : "70" }
----

* `java.lang.Byte[]` (or byte[])

[source, JSON]
----
  { "pdfAsBytes" : BinData(0,"MTIzNDU=") }
----

* `java.lang.Short` (or short primitive)

[source, JSON]
----
  { "urlPort" : 80 }
----

* `java.lang.Integer` (or integer primitive)

[source, JSON]
----
  { "stockCount" : 12309 }
----

* `java.lang.Long` (or long primitive)

[source, JSON]
----
  { "userId" : NumberLong("-6718902786625749549") }
----

* `java.lang.Float` (or float primitive)

[source, JSON]
----
  { "visitRatio" : 10.39 }
----

* `java.lang.Double` (or double primitive)

[source, JSON]
----
  { "tax_percentage" : 12.34 }
----

* `java.math.BigDecimal`

[source, JSON]
----
  { "site_weight" : "21.77" }
----

* `java.math.BigInteger`

[source, JSON]
----
  { "site_weight" : "444" }
----

* `java.util.Calendar`

[source, JSON]
----
  { "creation" : "2014/11/03 16:19:49:283 +0000" }
----

* `java.util.Date`

[source, JSON]
----
  { "last_update" : ISODate("2014-11-03T16:19:49.283Z") }
----

* `java.util.UUID`

[source, JSON]
----
  { "serialNumber" : "71f5713d-69c4-4b62-ad15-aed8ce8d10e0" }
----

* `java.util.URL`

[source, JSON]
----
  { "url" : "http://www.hibernate.org/" }
----

* `org.bson.types.ObjectId`

[source, JSON]
----
  { "object_id" : ObjectId("547d9b40e62048750f25ef77") }
----

[NOTE]
====
Hibernate OGM doesn't store null values in MongoDB,
setting a value to null is the same as removing the field
in the corresponding object in the db.

This can have consequences when it comes to queries on null value.
====

==== Entities

Entities are stored as MongoDB documents and not as BLOBs:
each entity property will be translated into a document field.
You can use `@Table` and `@Column` annotations
to rename respectively the collection the document is stored in
and the document's field a property is persisted in.

.Default JPA mapping for an entity
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
// Stored in the Collection "News"
{
    "_id" : "1234-5678-0123-4567",
    "title": "On the merits of NoSQL",
}
----
====

.Rename field and collection using @Table and @Column
====
[source, JAVA]
----
@Entity
// Overrides the collection name
@Table(name = "News_Collection")
public class News {

    @Id
    private String id;

    // Overrides the field name
    @Column(name = "headline")
    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
// Stored in the Collection "News"
{
    "_id" : "1234-5678-0123-4567",
    "headline": "On the merits of NoSQL",
}
----
====

===== Identifiers

[NOTE]
====
Hibernate OGM always store identifiers using the `_id` field of a MongoDB document ignoring
the name of the property in the entity.

That's a good thing as MongoDB has special treatment and expectation of the property `_id`.
====

An identifier type may be one of the <<mongodb-built-in-types,built-in types>>
or a more complex type represented by an embedded class.
When you use a built-in type, the identifier is mapped like a regular property.
When you use an embedded class, then the `_id` is representing a nested document
containing the embedded class properties.

.Define an identifier as a primitive type
====
[source, JAVA]
----
@Entity
public class Bookmark {

    @Id
    private String id;

    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
{
  "_id" : "bookmark_1"
  "title" : "Hibernate OGM documentation"
}
----
====

.Define an identifier using @EmbeddedId
====
[source, JAVA]
----
@Embeddable
public class NewsID implements Serializable {

    private String title;
    private String author;

    // getters, setters ...
}

@Entity
public class News {

    @EmbeddedId
    private NewsID newsId;
    private String content;

    // getters, setters ...
}
----

News collection as JSON in MongoDB

[source, JSON]
----

{
  "_id" : {
      "author" : "Guillaume",
      "title" : "How to use Hibernate OGM ?"
  },
  "content" : "Simple, just like ORM but with a NoSQL database"
}

----
====

Generally, it is recommended though to work with MongoDB's object id data type.
This will facilitate the integration with other applications expecting that common MongoDB id type.
To do so, you have two options:

* Define your id property as `org.bson.types.ObjectId`
* Define your id property as `String` and annotate it with `@Type(type="objectid")`

In both cases the id will be stored as native `ObjectId` in the datastore.

.Define an id as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private ObjectId id;

    private String title;

    // getters, setters ...
}
----
====

.Define an id of type String as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    @Type(type = "objectid")
    private String id;

    private String title;

    // getters, setters ...
}
----
====

===== Identifier generation strategies

You can assign id values yourself or let Hibernate OGM generate the value using the
`@GeneratedValue` annotation.

There are 4 different strategies:

1. <<mongodb-identity-id-generation-strategy, IDENTITY>> (suggested)
2. <<mongodb-table-id-generation-strategy, TABLE>>
3. <<mongodb-sequence-id-generation-strategy, SEQUENCE>>
4. <<mongodb-auto-id-generation-strategy, AUTO>>

[[mongodb-identity-id-generation-strategy]]
*1) IDENTITY generation strategy*

The preferable strategy, Hibernate OGM will create the identifier upon insertion.
To apply this strategy the id must be one of the following:

* annotated with `@Type(type="objectid")`
* `org.bson.types.ObjectId`

like in the following examples:

.Define an id of type String as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Type(type = "objectid")
    private String id;

    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : ObjectId("5425448830048b67064d40b1"),
    "title" : "Exciting News"
}
----
====

.Define an id as ObjectId
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private ObjectId id;

    private String title;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : ObjectId("5425448830048b67064d40b1"),
    "title" : "Exciting News"
}
----
====

[[mongodb-table-id-generation-strategy]]
*2) TABLE generation strategy*

.Id generation strategy TABLE using default values
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    private String name;

    // getters, setters ...
}

----

GuitarPlayer collection

[source, JSON]
----
{
    "_id" : NumberLong(1),
    "name" : "Buck Cherry"
}
----

hibernate_sequences collection

[source, JSON]
----
{
    "_id" : "GuitarPlayer",
    "next_val" : 101
}
----
====

.Id generation strategy TABLE using a custom table
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "guitarGen")
    @TableGenerator(
        name = "guitarGen",
        table = "GuitarPlayerSequence",
        pkColumnValue = "guitarPlayer",
        valueColumnName = "nextGuitarPlayerId"
    )
    private long id;

    // getters, setters ...
}

----

GuitarPlayer collection

[source, JSON]
----
{
    "_id" : NumberLong(1),
    "name" : "Buck Cherry"
}
----

GuitarPlayerSequence collection

[source, JSON]
----
{
    "_id" : "guitarPlayer",
    "nextGuitarPlayerId" : 2
}
----
====

*3) SEQUENCE generation strategy*

[[mongodb-sequence-id-generation-strategy]]
.SEQUENCE id generation strategy using default values
====
[source, JAVA]
----
@Entity
public class Song {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Long id;

  private String title;

  // getters, setters ...
}
----

Song collection

[source, JSON]
----
{
  "_id" : NumberLong(2),
  "title" : "Flower Duet"
}
----

hibernate_sequences collection

[source, JSON]
----
{ "_id" : "song_sequence_name", "next_val" : 21 }
----
====

[[mongodb-sequence-id-generation-strategy-custom]]
.SEQUENCE id generation strategy using custom values
====
[source, JAVA]
----
@Entity
public class Song {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "songSequenceGenerator")
  @SequenceGenerator(
      name = "songSequenceGenerator",
      sequenceName = "song_seq",
      initialValue = 2,
      allocationSize = 20
  )
  private Long id;

  private String title;

  // getters, setters ...
}
----

Song collection

[source, JSON]
----
{
  "_id" : NumberLong(2),
  "title" : "Flower Duet"
}
----

hibernate_sequences collection

[source, JSON]
----
{ "_id" : "song_seq", "next_val" : 42 }
----
====

[[mongodb-auto-id-generation-strategy]]
*4) AUTO generation strategy*

[WARNING]
====
Care must be taken when using the `GenerationType.AUTO` strategy.
When the property `hibernate.id.new_generator_mappings` is set to `false` (default),
it will map to the `IDENTITY` strategy.
As described before, this requires your ids to be of type `ObjectId` or `@Type(type = "objectid") String`.
If `hibernate.id.new_generator_mappings` is set to true, `AUTO` will be mapped to the `TABLE` strategy.
This requires your id to be of a numeric type.

We recommend to not use `AUTO` but one of the explicit strategies (`IDENTITY` or `TABLE`) to avoid
potential misconfigurations.

For more details you can check the issue https://hibernate.atlassian.net/browse/OGM-663[OGM-663].
====

If the property `hibernate.id.new_generator_mappings`  is set to `false`,
`AUTO` will behave as the `IDENTITY` strategy.

If the property `hibernate.id.new_generator_mappings`  is set to `true`,
`AUTO` will behave as the `SEQUENCE` strategy.

.AUTO id generation strategy using default values
====
[source, JAVA]
----
@Entity
public class DistributedRevisionControl {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String name;

  // getters, setters ...
}
----

DistributedRevisionControl collection

[source, JSON]
----
{ "_id" : NumberLong(1), "name" : "Git" }
----

hibernate_sequences collection

[source, JSON]
----
{ "_id" : "hibernate_sequence", "next_val" : 2 }
----
====

.AUTO id generation strategy wih `hibernate.id.new_generator_mappings` set to false and ObjectId
====
[source, JAVA]
----
@Entity
public class Comedian {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private ObjectId id;

  private String name;

  // getters, setters ...
}
----

Comedian collection

[source, JSON]
----
{ "_id" : ObjectId("5458b11693f4add0f90519c5"), "name" : "Louis C.K." }
----
====

.Entity with @EmbeddedId
====
[source, JAVA]
----
@Entity
public class News {

    @EmbeddedId
    private NewsID newsId;

    // getters, setters ...
}

@Embeddable
public class NewsID implements Serializable {

    private String title;
    private String author;

    // getters, setters ...
}
----

Rendered as JSON in MongoDB
[source, JSON]
----
{
    "_id" :{
        "title": "How does Hibernate OGM MongoDB work?",
        "author": "Guillaume"
    }
}
----
====

===== Embedded objects and collections

Hibernate OGM stores elements annotated with `@Embedded` or `@ElementCollection` as nested documents of the owning entity.

.Embedded object
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    @Embedded
    private NewsPaper paper;

    // getters, setters ...
}

@Embeddable
public class NewsPaper {

    private String name;
    private String owner;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : "1234-5678-0123-4567",
    "title": "On the merits of NoSQL",
    "paper": {
        "name": "NoSQL journal of prophecies",
        "owner": "Delphy"
    }
}
----
====

.@ElementCollection with primitive types
====
[source, JAVA]
----
@Entity
public class AccountWithPhone {

    @Id
    private String id;

    @ElementCollection
    private List<String> mobileNumbers;

    // getters, setters ...
}
----

AccountWithPhone collection

[source, JSON]
----
{
    "_id" : "john_account",
    "mobileNumbers" : [ "+1-222-555-0222", "+1-202-555-0333" ]
}
----
====

.@ElementCollection with one attribute
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : "df153180-c6b3-4a4c-a7da-d5de47cf6f00",
    "grandChildren" : [ "Luke", "Leia" ]
}
----
====

The class `GrandChild` has only one attribute `name`,
this means that Hibernate OGM doesn't need to store the name of the attribute.

If the nested document has two or more fields, like in the following example,
Hibernate OGM will store the name of the fields as well.

.@ElementCollection with @OrderColumn
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    @OrderColumn( name = "birth_order" )
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

[source, JSON]
----
{
    "_id" : "e3e1ed4e-c685-4c3f-9a67-a5aeec6ff3ba",
    "grandChildren" :
        [
            {
                "name" : "Luke",
                "birth_order" : 0
            },
            {
                "name" : "Leia",
                "birthorder" : 1
            }
        ]
}
----
====

.@ElementCollection with Map of @Embeddable
====
[source, JAVA]
----
@Entity
public class ForumUser {

	@Id
	private String name;

	@ElementCollection
	private Map<String, JiraIssue> issues = new HashMap<>();

    // getters, setters ...
}

@Embeddable
public class JiraIssue {

	private Integer number;
	private String project;

    // getters, setters ...
}
----

[source, JSON]
----
{
        "_id" : "Jane Doe",
        "issues" : {
                "issueWithNull" : {
                },
                "issue2" : {
                    "number" : 2000,
                    "project" : "OGM"
                },
                "issue1" : {
                    "number" : 1253,
                    "project" : "HSEARCH"
                }
        }
}
----
====

[NOTE]
====
You can override the column name used for a property of an embedded object.
But you need to know that the default column name is the concatenation of the embedding property,
a `.` (dot) and the embedded property (recursively for several levels of embedded objects).

The MongoDB datastore treats dots specifically as it transforms them into nested documents.
If you want to override one column name and still keep the nested structure, don't forget the dots.

That's a bit abstract, so let's use an example.

[source, JAVA]
----
@Entity
class Order {
    @Id String number;
    User user;
    Address shipping;
    @AttributeOverrides({
        @AttributeOverride(name="name", column=@Column(name="delivery.provider"),
        @AttributeOverride(name="expectedDelaysInDays", column=@Column(name="delivery.delays")
    })
    DeliveryProvider deliveryProvider;
    CreditCardType cardType;
}

// default columns
@Embedded
class User {
    String firstname;
    String lastname;
}

// override one column
@Embeddable
public Address {
    String street;
    @Column(name="shipping.dest_city")
    String city;
}

// both columns overridden from the embedding side
@Embeddable
public DeliveryProvider {
    String name;
    Integer expectedDelaysInDays;
}

// do not use dots in the overriding
// and mix levels (bad form)
@Embedded
class CreditCardType {
    String merchant;
    @Column(name="network")
    String network;
}
----

[source, JSON]
----
{
    "_id": "123RF33",
    "user": {
        "firstname": "Emmanuel",
        "lastname": "Bernard"
    },
    "shipping": {
        "street": "1 av des Champs Elysées",
        "dest_city": "Paris"
    },
    "delivery": {
        "provider": "Santa Claus Inc.",
        "delays": "1"
    }
    "network": "VISA",
    "cardType: {
        "merchant": "Amazon"
    }
}
----

If you share the same embeddable in different places, you can use JPA's `@AttributeOverride`
to override columns from the embedding side.
This is the case of `DeliveryProvider` in our example.

If you omit the dot in one of the columns, this column will not be part of the nested document.
This is demonstrated by the `CreditCardType`.
We advise you against it.
Like crossing streams, it is bad form.
This approach might not be supported in the future.
====

[[mongodb-associations]]
==== Associations

Hibernate OGM MongoDB proposes three strategies to store navigation information for associations.
The three possible strategies are:

* <<mongodb-in-entity-strategy, IN_ENTITY>> (default)
* <<mongodb-association-document-strategy, ASSOCIATION_DOCUMENT>>, using a global collection for all associations
* <<mongodb-collection-per-association-strategy, COLLECTION_PER_ASSOCIATION>>, using a dedicated collection for each association

To switch between these strategies, use of the three approaches to options:

* annotate your entity with `@AssocationStorage` and `@AssociationDocumentStorage` annotations (see <<ogm-mongodb-annotation-configuration>>),
* use the API for programmatic configuration (see <<ogm-mongodb-programmatic-configuration>>)
* or specify a default strategy via the `hibernate.ogm.datastore.document.association_storage` and
`hibernate.ogm.mongodb.association_document_storage` configuration properties.

[[mongodb-in-entity-strategy]]
===== In Entity strategy

* <<mongodb-in-entity-to-one-associations, *-to-one associations>>
* <<mongodb-in-entity-to-many-associations, *-to-many associations>>

In this strategy, Hibernate OGM stores the id(s) of the associated entity(ies)
into the entity document itself.
This field stores the id value for to-one associations and an array of id values for to-many associations.
An embedded id will be represented by a nested document.
For indexed collections (i.e. `List` or `Map`), the index will be stored along the id.

[NOTE]
====
When using this strategy the annotations `@JoinTable` will be ignored because no collection is created
for associations.

You can use `@JoinColumn` to change the name of the field that stores the foreign key (as an example, see
<<mongodb-in-entity-one-to-one-join-column>>).
====

[[mongodb-in-entity-to-one-associations]]
===== To-one associations

.Unidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Vehicle {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    private Vehicle vehicle;

    // getters, setters ...
}
----

[source, JSON]
----
{
  "_id" : "V_01",
  "brand" : "Mercedes"
}
----

Wheel collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "W001",
  "diameter" : 0,
  "vehicle_id" : "V_01"
}
----
====

[[mongodb-in-entity-one-to-one-join-column]]
.Unidirectional one-to-one with @JoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicle {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @JoinColumn( name = "part_of" )
    private Vehicle vehicle;

    // getters, setters ...
}
----

[source, JSON]
----
{
  "_id" : "V_01",
  "brand" : "Mercedes"
}
----

Wheel collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "W001",
  "diameter" : 0,
  "part_of" : "V_01"
}
----
====

In a true one-to-one association, it is possible to share the same id between the two entities
and therefore a foreign key is not required. You can see how to map this type of association in
the following example:

.Unidirectional one-to-one with @MapsId and @PrimaryKeyJoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicle {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @PrimaryKeyJoinColumn
    @MapsId
    private Vehicle vehicle;

    // getters, setters ...
}
----

Vehicle collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "V_01",
  "brand" : "Mercedes"
}
----

Wheel collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "V_01",
  "diameter" : 0,
}
----
====

.Bidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Husband {

    @Id
    private String id;
    private String name;

    @OneToOne
    private Wife wife;

    // getters, setters ...
}

@Entity
public class Wife {

    @Id
    private String id;
    private String name;

    @OneToOne
    private Husband husband;

    // getters, setters ...
}
----

Husband collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "alex",
  "name" : "Alex",
  "wife" : "bea"
}
----

Wife collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "bea",
  "name" : "Bea",
  "husband" : "alex"
}
----
====

.Unidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class JavaUserGroup {

    @Id
    private String jugId;
    private String name;

    // getters, setters ...
}

@Entity
public class Member {

    @Id
    private String id;
    private String name;

    @ManyToOne
    private JavaUserGroup memberOf;

    // getters, setters ...
}
----

JavaUserGroup collection as JSON in MongoDB

[source, JSON]
----
{
    "_id" : "summer_camp",
    "name" : "JUG Summer Camp"
}
----

Member collection as JSON in MongoDB

[source, JSON]
----
{
    "_id" : "jerome",
    "name" : "Jerome"
    "memberOf_jugId" : "summer_camp"
}
{
    "_id" : "emmanuel",
    "name" : "Emmanuel Bernard"
    "memberOf_jugId" : "summer_camp"
}
----
====

.Bidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class SalesForce {

    @Id
    private String id;
    private String corporation;

    @OneToMany(mappedBy = "salesForce")
    private Set<SalesGuy> salesGuys = new HashSet<SalesGuy>();

    // getters, setters ...
}

@Entity
public class SalesGuy {
    private String id;
    private String name;

    @ManyToOne
    private SalesForce salesForce;

    // getters, setters ...
}
----

SalesForce collection

[source, JSON]
----
{
    "_id" : "red_hat",
    "corporation" : "Red Hat",
    "salesGuys" : [ "eric", "simon" ]
}
----

SalesGuy collection

[source, JSON]
----
{
    "_id" : "eric",
    "name" : "Eric"
    "salesForce_id" : "red_hat",
}
{
    "_id" : "simon",
    "name" : "Simon",
    "salesForce_id" : "red_hat"
}
----
====

.Bidirectional many-to-one between entities with embedded ids
====
[source, JAVA]
----
@Entity
public class Game {

    @EmbeddedId
    private GameId id;

    private String name;

    @ManyToOne
    private Court playedOn;

    // getters, setters ...
}

public class GameId implements Serializable {

    private String category;

    @Column(name = "id.gameSequenceNo")
    private int sequenceNo;

    // getters, setters ...
    // equals / hashCode
}

@Entity
public class Court {

    @EmbeddedId
    private CourtId id;

    private String name;

    @OneToMany(mappedBy = "playedOn")
    private Set<Game> games = new HashSet<Game>();

    // getters, setters ...
}

public class CourtId implements Serializable {

    private String countryCode;
    private int sequenceNo;

    // getters, setters ...
    // equals / hashCode
}
----

.Court collection
[source, JSON]
----
{
    "_id" : {
        "countryCode" : "DE",
        "sequenceNo" : 123
    },
    "name" : "Hamburg Court",
    "games" : [
        { "gameSequenceNo" : 457, "category" : "primary" },
        { "gameSequenceNo" : 456, "category" : "primary" }
    ]
}
----

.Game collection
[source, JSON]
----
{
    "_id" : {
        "category" : "primary",
        "gameSequenceNo" : 456
    },
    "name" : "The game",
    "playedOn_id" : {
        "countryCode" : "DE",
        "sequenceNo" : 123
    }
}
{
    "_id" : {
        "category" : "primary",
        "gameSequenceNo" : 457
    },
    "name" : "The other game",
    "playedOn_id" : {
        "countryCode" : "DE",
        "sequenceNo" : 123
    }
}
----
====

Here we see that the embedded id is represented as a nested document
and directly referenced by the associations.

[[mongodb-in-entity-to-many-associations]]
===== To-many associations

.Unidirectional one-to-many
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide",
  "products" : [ "Beer", "Pretzel" ]
}
----

Product collection

[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----
====

.Unidirectional one-to-many with @OrderColumn
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide",
  "products" : [
    {
      "products_name" : "Pretzel",
      "products_ORDER" : 1
    },
    {
      "products_name" : "Beer",
      "products_ORDER" : 0
    }
  ]
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----
====

A map can be used to represent an association,
in this case Hibernate OGM will store the key of the map
and the associated id.

.Unidirectional one-to-many using maps with defaults
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    private Map<String, Address> addresses = new HashMap<String, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

User collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "user_001",
  "addresses" : [
    {
      "work" : "address_001",
      "home" : "address_002"
    }
  ]
}
----

Address collection as JSON in MongoDB

[source, JSON]
----
{ "_id" : "address_001", "city" : "Rome" }
{ "_id" : "address_002", "city" : "Paris" }
----
====

If the map value cannot be represented by a single field (e.g. when referencing a type with a composite id
or using an embeddable type as map value type),
a sub-document containing all the required fields will be stored as value.

If the map key either is not of type `String` or it is made up of several columns (composite map key),
the optimized structure shown in the example above cannot be used as MongoDB only allows for Strings as field names.
In that case the association will be represented by a list of sub-documents, also containing the map key column(s).
You can use `@MapKeyColumn` to rename the field containing the key of the map,
otherwise it will default to "<%COLLECTION_ROLE%>_KEY", e.g. "addresses_KEY".

.Unidirectional one-to-many using maps with @MapKeyColumn
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    @MapKeyColumn(name = "addressType")
    private Map<Long, Address> addresses = new HashMap<Long, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

User collection as JSON in MongoDB

[source, JSON]
----
{
  "_id" : "user_001",
  "addresses" : [
    {
      "addressType" : 1,
      "addresses_id" : "address_001"
    },
    {
      "addressType" : 2,
      "addresses_id" : "address_002"
    }
  ]
}
----

Address collection as JSON in MongoDB

[source, JSON]
----
{ "_id" : "address_001", "city" : "Rome" }
{ "_id" : "address_002", "city" : "Paris" }
----
====

In case you want to enforce the list-style represention also for maps with a single key column of type `String`
(e.g. when reading back data persisted by earlier versions of Hibernate OGM),
you can do so by setting the option `hibernate.ogm.datastore.document.map_storage` to the value `AS_LIST`.

.Unidirectional many-to-many using in entity strategy
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

Student collection

[source, JSON]
----
{
  "_id" : "john",
  "name" :"John Doe" }
{
  "_id" : "mario",
  "name" : "Mario Rossi"
}
{
  "_id" : "kate",
  "name" : "Kate Doe"
}
----

ClassRoom collection

[source, JSON]
----
{
  "_id" : NumberLong(1),
  "lesson" : "Math"
  "students" : [
     "mario",
     "john"
  ]
}
{
  "_id" : NumberLong(2),
  "lesson" : "English"
  "students" : [
     "mario",
     "kate"
  ]
}
----
====

.Bidirectional many-to-many
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany( mappedBy = "bankAccounts" )
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
    "_id" : "owner_1",
    "SSN" : "0123456"
    "bankAccounts" : [ "account_1" ]
}
----

BankAccount collection

[source, JSON]
----
{
    "_id" : "account_1",
    "accountNumber" : "X2345000"
    "owners" : [ "owner_1", "owner2222" ]
}
----
====

.Ordered list with embedded id
====
[source, JAVA]
----
@Entity
public class Race {
    @EmbeddedId
    private RaceId raceId;

    @OrderColumn(name = "ranking")
    @OneToMany @JoinTable(name = "Race_Runners")
    private List<Runner> runnersByArrival = new ArrayList<Runner>();

    // getters, setters ...
}

public class RaceId implements Serializable {
    private int federationSequence;
    private int federationDepartment;

    // getters, setters, equals, hashCode
}

@Entity
public class Runner {
    @EmbeddedId
    private RunnerId runnerId;
    private int age;

    // getters, setters ...
}

public class RunnerId implements Serializable {
    private String firstname;
    private String lastname;

    // getters, setters, equals, hashCode
}
----

.Race collection
[source, JSON]
----
{
    "_id": {
        "federationDepartment": 75,
        "federationSequence": 23
    },
    "runnersByArrival": [{
        "firstname": "Pere",
        "lastname": "Noel",
        "ranking": 1
    }, {
        "firstname": "Emmanuel",
        "lastname": "Bernard",
        "ranking": 0
    }]
}
----

.Runner collection
[source, JSON]
----
{
    "_id": {
        "firstname": "Pere",
        "lastname": "Noel"
    },
    "age": 105
} {
    "_id": {
        "firstname": "Emmanuel",
        "lastname": "Bernard"
    },
    "age": 37
}
----
====

[[mongodb-collection-per-association-strategy]]
===== One collection per association strategy

In this strategy, Hibernate OGM creates a MongoDB collection per association
in which it will store all navigation information for that particular association.

This is the strategy closest to the relational model.
If an entity A is related to B and C, 2 collections will be created.
The name of this collection is made of the association table concatenated with `associations_`.

For example, if the `BankAccount` and `Owner` are related,
the collection used to store will be named `associations_Owner_BankAccount`. You can rename
The prefix is useful to quickly identify the association collections from the entity collections.
You can also decide to rename the collection representing the association using `@JoinTable`
(see <<mongodb-one-collection-strategy-join-table, an example>>)

Each document of an association collection has the following structure:

* `_id` contains the id of the owner of relationship
* `rows` contains all the id of the related entities

[NOTE]
====
The preferred approach is to use the <<mongodb-in-entity-strategy, in-entity strategy>>
but this approach can alleviate the problem of having documents that are too big.
====

.Unidirectional relationship
====
[source, JSON]
----
{
    "_id" : { "owners_id" : "owner0001" },
    "rows" : [
        "accountABC",
        "accountXYZ"
    ]
}
----
====

.Bidirectional relationship
====
[source, JSON]
----
{
    "_id" : { "owners_id" : "owner0001" },
    "rows" : [ "accountABC", "accountXYZ" ]
}
{
    "_id" : { "bankAccounts_id" : "accountXYZ" },
    "rows" : [ "owner0001" ]
}
----
====

[NOTE]
====
This strategy won't affect *-to-one associations or embedded collections.
====

.Unidirectional one-to-many using one collection per strategy
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

associations_Basket_Product collection
[source, JSON]
----
{
  "_id" : { "Basket_id" : "davide_basket" },
  "rows" : [ "Beer", "Pretzel" ]
}
----
====

The order of the element in the list might be preserved using @OrderColumn.
Hibernate OGM will store the order adding an additional fieldd to the document
containing the association.

.Unidirectional one-to-many using one collection per strategy with @OrderColumn
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    @OrderColumn
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection

[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

associations_Basket_Product collection

[source, JSON]
----
{
  "_id" : { "Basket_id" : "davide_basket" },
  "rows" : [
    {
      "products_name" : "Pretzel",
      "products_ORDER" : 1
    },
    {
      "products_name" : "Beer",
      "products_ORDER" : 0
    }
  ]
}
----
====

.Unidirectional many-to-many using one collection per association strategy
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

Student collection

[source, JSON]
----
{
  "_id" : "john",
  "name" : "John Doe"
}
{
  "_id" : "mario",
  "name" : "Mario Rossi"
}
{
  "_id" : "kate",
  "name" : "Kate Doe"
}
----

ClassRoom collection

[source, JSON]
----
{
  "_id" : NumberLong(1),
  "lesson" : "Math"
}
{
  "_id" : NumberLong(2),
  "lesson" : "English"
}
----

associations_ClassRoom_Student

[source, JSON]
----
{
  "_id" : {
    "ClassRoom_id" : NumberLong(1),
  },
  "rows" : [ "john", "mario" ]
}
{
  "_id" : {
    "ClassRoom_id" : NumberLong(2),
  },
  "rows" : [ "mario", "kate" ]
}
----
====

.Bidirectional many-to-many using one collection per association strategy
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany(mappedBy = "bankAccounts")
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
  "_id" : "owner_1",
  "SSN" : "0123456"
}
----

BankAccount collection

[source, JSON]
----
{
  "_id" : "account_1",
  "accountNumber" : "X2345000"
}
----

associations_AccountOwner_BankAccount collection

[source, JSON]
----
{
  "_id" : {
    "bankAccounts_id" : "account_1"
  },
  "rows" : [ "owner_1" ]
}
{
  "_id" : {
    "owners_id" : "owner_1"
  },
  "rows" : [ "account_1" ]
}
----
====

[[mongodb-one-collection-strategy-join-table]]
You can change the name of the collection containing the association using the `@JoinTable` annotation.
In the following example, the name of the collection containing the association is `OwnerBankAccounts`
(instead of the default `associations_AccountOwner_BankAccount`)

.Bidirectional many-to-many using one collection per association strategy and @JoinTable
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    @JoinTable( name = "OwnerBankAccounts" )
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany(mappedBy = "bankAccounts")
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
  "_id" : "owner_1",
  "SSN" : "0123456"
}
----

BankAccount collection

[source, JSON]
----
{
  "_id" : "account_1",
  "accountNumber" : "X2345000"
}
----

OwnerBankAccount

[source, JSON]
----
{
  "_id" : {
    "bankAccounts_id" : "account_1"
  },
  "rows" : [ "owner_1" ]
}
{
  "_id" : {
    "owners_id" : "owner_1"
  },
  "rows" : [ "account_1" ]
}
----
====

[[mongodb-association-document-strategy]]
===== Global collection strategy

With this strategy, Hibernate OGM creates a single collection named `Associations`
in which it will store all navigation information for all associations.
Each document of this collection is structured in 2 parts.
The first is the `_id` field which contains the identifier information
of the association owner and the name of the association table.
The second part is the `rows` field which stores (into an embedded collection) all ids
that the current instance is related to.

[NOTE]
====
This strategy won't affect *-to-one associations or embedded collections.

Generally, you should not make use of this strategy
unless embedding the association information proves to be too big for your document
and you wish to separate them.
====

.Associations collection containing unidirectional association
====
[source, JSON]
----
{
    "_id": {
        "owners_id": "owner0001",
        "table": "AccountOwner_BankAccount"
    },
    "rows": [ "accountABC", "accountXYZ" ]
}
----
====

For a bidirectional relationship, another document is created where ids are reversed.
Don't worry, Hibernate OGM takes care of keeping them in sync:

.Associations collection containing a bidirectional association
====
[source, JSON]
----
{
    "_id": {
        "owners_id": "owner0001",
        "table": "AccountOwner_BankAccount"
    },
    "rows": [ "accountABC", "accountXYZ" ]
}
{
    "_id": {
        "bankAccounts_id": "accountXYZ",
        "table": "AccountOwner_BankAccount"
    },
    "rows": [ "owner0001" ]
}
----
====

.Unidirectional one-to-many using global collection strategy
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

Associations collection
[source, JSON]
----
{
  "_id" : {
    "Basket_id" : "davide_basket",
    "table" : "Basket_Product"
  },
  "rows" : [
    {
      "products_name" : "Pretzel",
      "products_ORDER" : 1
    },
    {
      "products_name" : "Beer",
    "products_ORDER" : 0
    }
  ]
}
----
====

.Unidirectional one-to-many using global collection strategy with `@JoinTable`
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    // It will change the value stored in the field table in the Associations collection
    @JoinTable( name = "BasketContent" )
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

Basket collection

[source, JSON]
----
{
  "_id" : "davide_basket",
  "owner" : "Davide"
}
----

Product collection
[source, JSON]
----
{
  "_id" : "Pretzel",
  "description" : "Glutino Pretzel Sticks"
}
{
  "_id" : "Beer",
  "description" : "Tactical nuclear penguin"
}
----

Associations collection

[source, JSON]
----
{
  "_id" : {
    "Basket_id" : "davide_basket",
    "table" : "BasketContent"
  },
  "rows" : [ "Beer", "Pretzel" ]
}
----
====

.Unidirectional many-to-many using global collection strategy
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

Student collection

[source, JSON]
----
{
  "_id" : "john",
  "name" : "John Doe"
}
{
  "_id" : "mario",
  "name" : "Mario Rossi"
}
{
  "_id" : "kate",
  "name" : "Kate Doe"
}
----

ClassRoom collection

[source, JSON]
----
{
  "_id" : NumberLong(1),
  "lesson" : "Math"
}
{
  "_id" : NumberLong(2),
  "lesson" : "English"
}
----

Associations collection

[source, JSON]
----
{
  "_id" : {
    "ClassRoom_id" : NumberLong(1),
    "table" : "ClassRoom_Student"
  },
  "rows" : [ "john", "mario" ]
}
{
  "_id" : {
    "ClassRoom_id" : NumberLong(2),
    "table" : "ClassRoom_Student"
  },
  "rows" : [ "mario", "kate" ]
}
----
====

.Bidirectional many-to-many using global collection strategy
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany(mappedBy = "bankAccounts")
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

AccountOwner collection

[source, JSON]
----
{
  "_id" : "owner0001",
  "SSN" : "0123456"
}
----

BankAccount collection

[source, JSON]
----
{
  "_id" : "account_1",
  "accountNumber" : "X2345000"
}
----

Associations collection

[source, JSON]
----
{
  "_id" : {
    "bankAccounts_id" : "account_1",
    "table" : "AccountOwner_BankAccount"
    },

  "rows" : [ "owner0001" ]
}
{
  "_id" : {
    "owners_id" : "owner0001",
    "table" : "AccountOwner_BankAccount"
  },

  "rows" : [ "account_1" ]
}
----
====

[[ogm-mongodb-indexes-unique-constraints]]
=== Indexes and unique constraints

==== Standard indexes and unique constraints

You can create your index and unique constraints in MongoDB using the standard JPA annotations.

.Creating indexes and unique constraints using JPA annotations
====
[source, JAVA]
----
@Entity
@Table(indexes = {
    @Index(columnList = "author, name", name = "author_name_idx", unique = true),
    @Index(columnList = "name DESC", name = "name_desc_idx")
})
public class Poem {

    @Id
    private String id;
    private String name;
    private String author;

    @Column(unique = true)
    private String url;

   // getters, setters ...
}
----
====

[NOTE]
====
MongoDB supports unique constraints via unique indexes. It considers `null` as a value to be unique: you can only
have one `null` value per unique index. This is not what is commonly accepted as the definition of a unique constraint in
the JPA world. Thus, by default, we create the unique indexes as `sparse`: it only indexes defined values so that the
unique constraints accept multiple `null` values.
====

==== Using MongoDB specific index options

MongoDB supports https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/[a number of options for
index creation].

It is possible to define them using the `@IndexOption` annotation.

.Creating indexes with MongoDB specific options
====
[source, JAVA]
----
@Entity
@Table(indexes = {
    @Index(columnList = "author", name = "author_idx")
})
@IndexOptions(
    @IndexOption(forIndex = "author_idx", options = "{ background : true, sparse : true, partialFilterExpression : { author: 'Verlaine' } }")
)
public class Poem {

    @Id
    private String id;
    private String name;
    private String author;

   // getters, setters ...
}
----
====

`@IndexOption` simply passes the options to MongoDB at index creation: you can use every option available in MongoDB.

==== Full text indexes

MongoDB supports the ability to create one (and only one) full text index per collection.

As JPA does not support the ability to define `text` as an order in the `@Index` annotation (only `ASC` and `DESC`
are supported), this ability has been included inside the `@IndexOption` mechanism. You simply need to add `text: true`
to the options passed to MongoDB, Hibernate OGM interprets it and translates the index to a full text index.

.Creating a full text index
====
[source, JAVA]
----
@Entity
@Table(indexes = {
    @Index(columnList = "author, name", name = "author_name_text_idx")
})
@IndexOptions(
    @IndexOption(forIndex = "author_name_text_idx", options = "{ text: true, default_language : 'fr', weights : { author: 2, name: 5 } }")
)
public class Poem {

    @Id
    private String id;
    private String name;
    private String author;

   // getters, setters ...
}
----
====

=== Transactions

MongoDB does not support transactions.
Only changes applied to the same document are done atomically.
A change applied to more than one document will not be applied atomically.
This problem is slightly mitigated by the fact that Hibernate OGM queues all changes
before applying them during flush time.
So the window of time used to write to MongoDB is smaller than what you would have done manually.

We recommend that you still use transaction demarcations with Hibernate OGM
to trigger the flush operation transparently (on commit).
But do not consider rollback as a possibility, this won't work.

[[ogm-mongodb-optimisticlocking]]
=== Optimistic Locking

MongoDB does not provide a built-in mechanism for detecting concurrent updates to the same document
but it provides a way to execute atomic find and update operations.
By exploiting this commands Hibernate OGM can detect concurrent modifications to the same document.

You can enable optimistic locking detection using the annotation `@Version`:

.Optimistic locking detection via `@Version`
====
[source, JAVA]
----
@Entity
public class Planet implements Nameable {

    @Id
    private String id;
    private String name;

    @Version
    private int version;

   // getters, setters ...
}
----

----
{
  "_id" : "planet-1",
  "name" : "Pluto",
  "version" : 0
}
----
====

The `@Version` annotation define which attribute will keep track of the version of the document,
Hibernate OGM will update the field when required and if two changes from two different sessions (for example)
are applied to the same document a `org.hibernate.StaleObjectStateException` is thrown.

You can use `@Column` to change the name of the field created on MongoDB:

.Optimistic locking detection via `@Version` using `@Column`
====
[source, JAVA]
----
@Entity
public class Planet implements Nameable {

    @Id
    private String id;
    private String name;

    @Version
    @Column(name="OPTLOCK")
    private int version;

   // getters, setters ...
}
----

----
{
  "_id" : "planet-1",
  "name" : "Pluto",
  "OPTLOCK" : 0
}
----
====

[[ogm-mongodb-queries]]
=== Queries

You can express queries in a few different ways:

* using JPQL
* using a native MongoQL query
* using a Hibernate Search query (brings advanced full-text and geospatial queries)

While you can use JPQL for simple queries, you might hit limitations.
The current recommended approach is to use native MongoQL
if your query involves nested (list of) elements.

MongoDB doesn't require Hibernate Search to run queries.

[NOTE]
====
In order to reflect changes performed in the current session,
all entities affected by a given query are flushed to the datastore prior to query execution
(that's the case for Hibernate ORM as well as Hibernate OGM).

For not fully transactional stores such as MongoDB
this can cause changes to be written as a side-effect of running queries
which cannot be reverted by a possible later rollback.

Depending on your specific use cases and requirements you may prefer to disable auto-flushing,
e.g. by invoking `query.setFlushMode( FlushMode.MANUAL )`.
Bear in mind though that query results will then not reflect changes applied within the current session.
====

==== JPQL queries

Hibernate OGM is a work in progress, so only a sub-set of JPQL constructs is available
when using the JPQL query support. This includes:

* simple comparisons using "<", "+<=+", "=", ">=" and ">"
* `IS NULL` and `IS NOT NULL`
* the boolean operators `AND`, `OR`, `NOT`
* `LIKE`, `IN` and `BETWEEN`
* `ORDER BY`
* inner `JOIN` on embedded collections
* projections of regular and embedded properties

Queries using these constructs will be transformed into equivalent native MongoDB queries.

[NOTE]
====
Let us know <<ogm-howtocontribute,by opening an issue or sending an email>>
what query you wish to execute.
Expanding our support in this area is high on our priority list.
====

[[ogm-mongodb-queries-native]]
==== Native MongoDB queries

Hibernate OGM also supports certain forms of native queries for MongoDB.
Currently two forms of native queries are available via the MongoDB backend:

* find queries specifying the search criteria only
* queries specified using the MongoDB CLI syntax (<<ogm-mongodb-cli-syntax>>)

The former always maps results to entity types.
The latter either maps results to entity types or to certain supported forms of projection.
Note that parameterized queries are not supported by MongoDB, so don't expect `Query#setParameter()` to work.

You can execute native queries as shown in the following example:

.Using the JPA API
====
[source, JAVA]
----
@Entity
public class Poem {

    @Id
    private Long id;

    private String name;

    private String author;

   // getters, setters ...
}

...

javax.persistence.EntityManager em = ...

// criteria-only find syntax
String query1 = "{ $and: [ { name : 'Portia' }, { author : 'Oscar Wilde' } ] }";
Poem poem = (Poem) em.createNativeQuery( query1, Poem.class ).getSingleResult();

// criteria-only find syntax with order-by
String query2 = "{ $query : { author : 'Oscar Wilde' }, $orderby : { name : 1 } }";
List<Poem> poems = em.createNativeQuery( query2, Poem.class ).getResultList();

// projection via CLI-syntax
String query3 = "db.WILDE_POEM.find(" +
    "{ '$query' : { 'name' : 'Athanasia' }, '$orderby' : { 'name' : 1 } }" +
    "{ 'name' : 1 }" +
    ")";

// will contain name and id as MongoDB always returns the id for projections
List<Object[]> poemNames = (List<Object[]>)em.createNativeQuery( query3 ).getResultList();

// projection via CLI-syntax
String query4 = "db.WILDE_POEM.count({ 'name' : 'Athanasia' })";

Object[] count = (Object[])em.createNativeQuery( query4 ).getSingleResult();
----
====

The result of a query is a managed entity (or a list thereof) or a projection of attributes in form of an object array,
just like you would get from a JPQL query.

.Using the Hibernate native API
====
[source, JAVA]
----
OgmSession session = ...

String query1 = "{ $and: [ { name : 'Portia' }, { author : 'Oscar Wilde' } ] }";
Poem poem = session.createNativeQuery( query1 )
                      .addEntity( "Poem", Poem.class )
                      .uniqueResult();

String query2 = "{ $query : { author : 'Oscar Wilde' }, $orderby : { name : 1 } }";
List<Poem> poems = session.createNativeQuery( query2 )
                      .addEntity( "Poem", Poem.class )
                      .list();
----
====

Native queries can also be created using the `@NamedNativeQuery` annotation:

.Using @NamedNativeQuery
====
[source, JAVA]
----
@Entity
@NamedNativeQuery(
   name = "AthanasiaPoem",
   query = "{ $and: [ { name : 'Athanasia' }, { author : 'Oscar Wilde' } ] }",
   resultClass = Poem.class )
public class Poem { ... }

...

// Using the EntityManager
Poem poem1 = (Poem) em.createNamedQuery( "AthanasiaPoem" )
                     .getSingleResult();

// Using the Session
Poem poem2 = (Poem) session.getNamedQuery( "AthanasiaPoem" )
                     .uniqueResult();
----
====

Hibernate OGM stores data in a natural way so you can still execute queries using the
MongoDB driver, the main drawback is that the results are going to be raw MongoDB
documents and not managed entities.

[[ogm-mongodb-cli-syntax]]

===== CLI Syntax

Hibernate OGM can execute native queries expressed using the MongoDB CLI syntax with some limitations.
Currently `find()`, `findOne()`, `findAndModify()`, and `count()` queries are supported. Furthermore, three
types of write queries are supported via the CLI syntax: `insert()`, `remove()`, and `update()`. Other query
types may be supported in future versions.

As one would expect, `find()`, `findOne()`, `findAndModify()`, `aggregate`,
`distinct()`, and `count()` can be executed using
`javax.persistence.Query.getSingleResult()` or `javax.persistence.Query.getResultList()`, while `insert()`,
`remove()`, and `update()` require using `javax.persistence.Query.executeUpdate()`. Also note that,
`javax.persistence.Query.executeUpdate()` may return `-1` in case execution of a query was not acknowledged
relative to the write concern used.
Via `javax.persistence.Query.executeUpdate()` it is also possible to run `db.Collection.drop()`
queries.

[NOTE]
====
`db.Collection.drop()` will always return 1. This is because the underlying driver we are
using doesn't return any value after the execution of the operation.
====

The following functions can be used in the provided JSON:
`BinData`, `Date`, `HexData`, `ISODate`, `NumberLong`, `ObjectId`, `Timestamp`,
`RegExp`, `DBPointer`, `UUID`, `GUID`, `CSUUID`, `CSGUID`, `JUUID`, `JGUID`, `PYUUID`, `PYGUID`.

[NOTE]
====
`NumberInt` is not supported as it is currently not supported by the MongoDB Java driver.
====

No cursor operations such as `sort()` are supported.
Instead use the corresponding MongoDB http://docs.mongodb.org/manual/reference/operator/query-modifier/[query modifiers]
such as `$orderby` within the criteria parameter.

You can limit the results of a query using the `setMaxResults(...)` method.

JSON parameters passed via the CLI syntax must be specified using the
http://docs.mongodb.org/manual/reference/mongodb-extended-json/[strict mode].
Specifically, keys need to be given within quotes; the only relaxation of this is that single quotes
may be used when specifying attribute names/values to facilitate embedding queries within
Java strings.

Note that results of projections are returned as retrieved from the MongoDB driver at the moment and
are not (yet) converted using suitable Hibernate OGM type implementations.
This requirement is tracked under https://hibernate.atlassian.net/browse/OGM-1031[OGM-1031].

.CLI syntax examples
====
[source, JAVA]
----

// Valid syntax
String valid = "db.Poem.find({ \"name\" : \"Athanasia\" })";

String alsoValid = "db.Poem.find({ '$or' : [{'name': 'Athanasia' }, {'name': 'Portia' }]})";

String validAggregation = "db.Poem.aggregate([{ '$match': {'author': { '$regex': 'oscar.*', '$options': 'i' } } }, { '$sort': {'name': -1 } } ])";

// NOT Valid syntax, it will throw an exception: com.mongodb.util.JSONParseException
String notValid =  "db.Poem.find({ name : \"Athanasia\" })";

String alsoNotValid = "db.Poem.find({ $or : [{name: 'Athanasia' }, {name: 'Portia' }]})";

----
====

.CLI syntax sort and limit results alternatives
====
[source, JAVA]
----
String nativeQuery = "db.Poem.find({ '$query': { 'author': 'Oscar Wilde' }, '$orderby' : { 'name' : 1 } })";

// Using hibernate session
List<Poem> result = session.createNativeQuery( nativeQuery )
	.addEntity( Poem.class )
	.setMaxResults( 2 )
	.list();

// Using JPA entity manager
List<Poem> results = em.createNativeQuery( nativeQuery, Poem.class )
	.setMaxResults( 2 )
	.getResultList();
----
====

.CLI syntax update examples
====
[source, JAVA]
----
String updateQuery = "db.Poem.findAndModify({ 'query': {'_id': 1}, 'update': { '$set': { 'author': 'Oscar Wilde' } }, 'new': true })";
List<Poem> updated = session.createNativeQuery( updateQuery ).addEntity( Poem.class ).list();

String insertQuery = "db.Poem.insert({ '_id': { '$numberLong': '11' }, 'author': 'Oscar Wilder', 'name': 'The one and wildest', 'rating': '1' } )";
int inserted = session.createNativeQuery( insertQuery ).executeUpdate();

String removeQuery = "db.Poem.remove({ '_id': { '$numberLong': '11' } })";
int removed = session.createNativeQuery( removeQuery ).executeUpdate();
----
====

[WARNING]
====
Support for the `$regexp` operator is limited to the string syntax. We do not support the `/pattern/` syntax as it is not
currently supported by the MongoDB Java driver.

[source, JAVA]
----
// Valid syntax
String nativeQuery = "{ $query : { author : { $regex : '^Oscar' } }, $orderby : { name : 1 } }";
List<Poem> result = session.createNativeQuery( nativeQuery ).addEntity( Poem.class ).list();
----
====

[[ogm-mongodb-stored-proc-native]]

==== Server-side JavaScript and stored procedures

[NOTE]
====
This is an experimental feature.
====

In MongoDB, it is possible to call server-side JavaScript as if it is a stored procedure.
You can use the existing methods in JPA:

.Calling server-side JavaScript with positional parameters
====
[source, JAVA]
----
  @Entity
  public class Car {
    @Id
    private Integer id;

    private String brand;

    ...
  }

  EntityManager em = ...
  StoredProcedureQuery storedProcedureQuery = em.createStoredProcedureQuery( "findMostExpensiveCars", Car.class );
  storedProcedureQuery.registerStoredProcedureParameter( "year", Integer.class, ParameterMode.IN );
  storedProcedureQuery.setParameter( "year", 1995 );
  List<Car> cars = storedProcedureQuery.getResultList();
----
====

This example will work assuming that there is a `findMostExpensiveCars` JavaScript function in MongoDB
and that the result of the function is a list of cars that can be mapped to the `Car` entity.

.Calling server-side JavaScript with Hibernate OGM with positional parameters
====
[source, JSON]
----
{
  "result" : [
    { "id":1, "brand":"Bentley" },
    { "id":2, "brand":"Maserati" },
  ]
}
----
====

More details about server-side functions can be found in
https://docs.mongodb.com/manual/core/server-side-JavaScript[the MongoDB reference documentation].

==== Hibernate Search

You can index your entities using Hibernate Search.
That way, a set of secondary indexes independent of MongoDB is maintained by Hibernate Search
and you can run Lucene queries on top of them.
The benefit of this approach is a nice integration at the JPA / Hibernate API level
(managed entities are returned by the queries).
The drawback is that you need to store the Lucene indexes somewhere
(file system, infinispan grid, etc).
Have a look at the Infinispan section (<<ogm-infinispan-indexstorage>>)
for more info on how to use Hibernate Search.

=== Geospatial support

==== Geospatial fields

Our MongoDB integration supports the ability to declare geospatial fields by using specific Java types that will be
automatically converted to GeoJSON objects stored in MongoDB.

We currently support the following types:

 * `GeoPoint`, stored as a GeoJSON Point
 * `GeoMultiPoint`, stored as a GeoJSON MultiPoint
 * `GeoLineString`, stored as a GeoJSON LineString
 * `GeoMultiLineString`, stored as a GeoJSON MultiLineString
 * `GeoPolygon`, stored as a GeoJSON Polygon
 * `GeoMultiPolygon`, stored as a GeoJSON MultiPolygon

You can find more information about these types and their constraints in the
https://docs.mongodb.com/manual/reference/geojson/[MongoDB documentation].

.Declaring a geospatial field
====
[source, JAVA]
----
@Entity
public class Restaurant {

    // [...]

    private GeoPoint location;
}
----
====

These Java types come with handy constructors and helpers to help manipulate them.

.Instantiating a polygon
====
[source, JAVA]
----
GeoPolygon polygon = new GeoPolygon(
        new GeoPoint( 4.814922, 45.7753612 ),
        new GeoPoint( 4.8160825, 45.7327172 ),
        new GeoPoint( 4.9281299, 45.7211302 ),
        new GeoPoint( 4.8706127, 45.786724 ),
        new GeoPoint( 4.814922, 45.7753612 )
);
----
====

==== Geospatial indexes and queries

To be able to run optimized queries on geospatial fields, you need to declare spatial indexes.

You can leverage your usual annotations to declare the indexes directly on your entities.

.Declaring a geospatial index
====
[source, JAVA]
----
@Entity
@Table(indexes = {
		@Index(columnList = "location", name = "location_spatial_idx")
})
@IndexOptions(
		@IndexOption(forIndex = "location_spatial_idx", options = "{ _type: '2dsphere' }")
)
public class Restaurant {

    // [...]

    private GeoPoint location;
}
----
====

Note that you need to precise the type of the index using an `@IndexOption` annotation.

The next step is to execute a geospatial query using a native query.

.Finding entities around a point
====
[source, JAVA]
----
GeoPoint geoPoint = new GeoPoint( 4.8520035, 45.7498209 );

Query query = session
        .createNativeQuery( "{ location: { $near: { $geometry: " + geoPoint.toBsonDocument() + ", $maxDistance: 500 } } }" )
        .addEntity( Restaurant.class );
List<Restaurant> result = query.list();
----
====

.Finding entities within a polygon
====
[source, JAVA]
----
GeoPolygon geoPolygon = new GeoPolygon(
        new GeoPoint( 4.814922, 45.7753612 ),
        new GeoPoint( 4.8160825, 45.7327172 ),
        new GeoPoint( 4.9281299, 45.7211302 ),
        new GeoPoint( 4.8706127, 45.786724 ),
        new GeoPoint( 4.814922, 45.7753612 )
);

Query query = session
        .createNativeQuery( "{ location: { $geoWithin: { $geometry: " + geoPolygon.toBsonDocument() + " } } }" )
        .addEntity( Restaurant.class );
List<Restaurant> result = query.list();
----
====

To learn more about MongoDB spatial indexes and queries, please refer to the
https://docs.mongodb.com/manual/geospatial-queries/[MongoDB documentation].