diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000000..526c385d348
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,3 @@
+public/
+resources/_gen/
+.hugo_build.lock
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000000..2bce54b59ab
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,10 @@
+.PHONY: build serve clean
+
+build:
+ hugo --minify
+
+serve:
+ hugo server -D
+
+clean:
+ rm -rf public/
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000000..d8898ae01e2
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,19 @@
+# Morphia Documentation
+
+This folder contains the Hugo-based documentation for Morphia.
+
+## Building
+
+```bash
+# Install Hugo (https://gohugo.io/installation/)
+# Then run:
+make serve # For local development
+make build # For production build
+```
+
+## Structure
+
+- `content/` - Markdown documentation files
+- `layouts/` - HTML templates
+- `static/` - Static assets (CSS, images, etc.)
+- `data/` - Data files for menus and configuration
diff --git a/docs/antora.yml b/docs/antora.yml
deleted file mode 100644
index 4ce15a0082d..00000000000
--- a/docs/antora.yml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-name: "morphia"
-title: "Morphia"
-version: "3.0"
-prerelease: "-SNAPSHOT"
-nav:
-- "modules/ROOT/nav.adoc"
-asciidoc:
- attributes:
- version: "3.0.0-SNAPSHOT"
- srcRef: "https://github.com/MorphiaOrg/morphia/blob/master"
\ No newline at end of file
diff --git a/docs/archetypes/default.md b/docs/archetypes/default.md
new file mode 100644
index 00000000000..26f317f303e
--- /dev/null
+++ b/docs/archetypes/default.md
@@ -0,0 +1,5 @@
+---
+title: "{{ replace .Name "-" " " | title }}"
+date: {{ .Date }}
+draft: true
+---
diff --git a/docs/content/features/aggregations.md b/docs/content/features/aggregations.md
new file mode 100644
index 00000000000..2450cfc0c98
--- /dev/null
+++ b/docs/content/features/aggregations.md
@@ -0,0 +1,100 @@
+---
+title: "Aggregations"
+weight: 9
+description: "Learn how to use MongoDB's aggregation framework with Morphia to define pipelines and transform data."
+---
+
+## Aggregations
+
+The [aggregation framework](https://docs.mongodb.com/manual/aggregation) in MongoDB allows you to define a series (called a pipeline) of operations (called stages) against the data in a collection.
+These pipelines can be used for analytics or they can be used to convert your data from one form to another.
+This guide will not go in to the details of how aggregation works, however.
+The official MongoDB [documentation](https://docs.mongodb.com/manual/aggregation) has extensive tutorials on such details.
+Rather, this guide will focus on the Morphia API. The examples shown here are taken from the
+[tests](https://github.com/MorphiaOrg/morphia/blob/master/morphia/src/test/java/dev/morphia/aggregation/AggregationTest.java) in Morphia itself. You can find the full list in the [Supported Operators](#supported-operators) section.
+
+Writing an aggregation pipeline starts just like writing a standard query.
+As with querying, we start with the `Datastore`:
+
+```java
+// Example aggregation code
+// See TestDocsExamples.java for full examples
+```
+
+`aggregate()` takes a `Class` literal. This lets Morphia know which collection to perform this aggregation against. Because of the transformational operations available in the aggregation [pipeline](https://docs.mongodb.com/manual/core/aggregation-pipeline), Morphia can not validate as much as it can with querying so care will need to be taken to ensure document fields actually exist when referencing them in your pipeline.
+
+### The Pipeline
+
+Aggregation pipelines are comprised of a series stages.
+Our example here with the `group()` stage. This method is the Morphia equivalent of the
+[$group](https://docs.mongodb.com/manual/reference/operator/aggregation/group/) operator. This stage, as the name suggests, groups together documents based on
+various criteria. In this example, we are defining the group ID as the `author` field which will collect all the books by the author
+together.
+
+The next step defines a new field, `books` comprised of the titles of the books found in each document. (For reference, this example is
+the Morphia equivalent of an [example](https://docs.mongodb.com/manual/reference/operator/aggregation/group/#group-title-by-author) found in the aggregation tutorials.) This results in a series of documents that look like this:
+
+```json
+{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] }
+{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }
+```
+
+### Executing the Pipeline
+
+Once your pipeline is complete, you can execute it via the `execute()` method.
+This method optionally takes a `Class` reference for the target type of your aggregation.
+Given this type, Morphia will map each document in the results and return it.
+Additionally, you can also include some options to `execute()`.
+We can use the various options on the
+[AggregationOptions](/javadoc/dev/morphia/aggregation/AggregationOptions.html) class to configure how we want the pipeline to execute.
+
+#### $out
+
+Depending your use case, you might not want to return the results of your aggregation but simply output them to another collection.
+That's where `$out` comes in. [$out](https://docs.mongodb.com/manual/reference/operator/aggregation/out/) is an operator that allows the results of a pipeline to be stored in to a named collection.
+This collection can not be sharded or a capped collection, however. This collection, if it does not exist, will be created upon execution of the pipeline.
+
+{{% notice warning %}}
+Any existing data in the collection will be replaced by the output of the aggregation.
+{{% /notice %}}
+
+An example aggregation using the `$out` stage looks like this:
+
+```java
+// Example using $out stage
+// See TestDocsExamples.java for full examples
+```
+
+You'll note that `out()` is the final stage. `$out` and `$merge` must be the final stage in our pipeline. We pass a type to `out()`
+that reflects the collection we want to write our output to. Morphia will use the type-to-collection mapping you've defined when mapping
+your entities to determine that collection name. You may also pass a String with the collection name as well if the target collection
+does not correspond to a mapped entity.
+
+#### $merge
+
+[$merge](https://docs.mongodb.com/manual/reference/operator/aggregation/merge/) is a very similar option with a some major differences.
+The biggest difference is that `$merge` can write to existing collections without destroying the existing documents. `$out` would
+overwrite any existing documents and replace them with the results of the pipeline. `$merge`, however, can deposit these new results alongside existing data and update existing data.
+
+Using `$merge` might look something like this:
+
+```java
+// Example using $merge stage
+// See TestDocsExamples.java for full examples
+```
+
+Much like `out()` above, for `merge()` we pass in a collection information but here we are also passing in which database to find/create
+the collection in. A merge is slightly more complex and so has more options to consider.
+In this example, we're merging in to the `budgets` collection in the `reporting` database and merging any existing documents based on the`_id` as denoted using the `on()` method.
+Because there may be existing data in the collection, we need to instruct the operation how to handle those cases.
+In this example, when documents matching we're choosing to replace them and when they don't we're instructing the operation to insert the
+new documents in to the collection. Other options are defined on `com.mongodb.client.model.MergeOptions` type defined by the Java driver.
+
+### Supported Operators
+Every effort is made to provide 100% coverage of all the operators offered by MongoDB. A select handful of operators have been excluded
+for reasons of suitability in Morphia. In short, some operators just don't make sense in Morphia. Below is listed all the currently
+supported operators. To see an example of an operator in action, click through to see the test cases for that operator.
+
+If an operator is missing and you think it should be included, please file an [issue](https://github.com/MorphiaOrg/morphia/issues) for that operator.
+
+For detailed information on stages and expressions, see the MongoDB [Aggregation Pipeline Operators documentation](https://docs.mongodb.com/manual/reference/operator/aggregation/).
diff --git a/docs/content/features/deletes.md b/docs/content/features/deletes.md
new file mode 100644
index 00000000000..e7c5f35706f
--- /dev/null
+++ b/docs/content/features/deletes.md
@@ -0,0 +1,21 @@
+---
+title: "Deletes"
+weight: 8
+description: "Learn how to delete documents from the database using Morphia queries"
+---
+
+## Deletes
+
+Queries are used to delete documents from the database as well.
+Using
+[Query#delete()](/javadoc/dev/morphia/query/Query.html#delete()), we can delete documents matching the query.
+The default operation will only delete the first matching document.
+However, you can opt to delete all matches by passing in the appropriate options:
+
+```java
+datastore
+ .find(Hotel.class)
+ .filter(gt("stars", 100))
+ .delete(new DeleteOptions()
+ .multi(true));
+```
diff --git a/docs/content/features/indexing.md b/docs/content/features/indexing.md
new file mode 100644
index 00000000000..36f7547c0fd
--- /dev/null
+++ b/docs/content/features/indexing.md
@@ -0,0 +1,129 @@
+---
+title: "Indexing"
+weight: 4
+description: "Define and manage indexes for MongoDB collections using Morphia annotations at the class and field level."
+---
+
+## Indexing
+
+Morphia provides annotations that allow developers to define indexes for a collection to be defined alongside the other mapping data on an entity's source.
+In addition to the familiar ascending/descending index types, Morphia and MongoDB support
+[TTL](https://docs.mongodb.com/manual/core/index-ttl/), [text](https://docs.mongodb.com/manual/core/index-text/), and [geospatial](https://docs.mongodb.com/manual/applications/geospatial-indexes/)
+indexes.
+When defining [text indexes](#text-indexing), there are certain restrictions which will be covered below.
+Full details for all these types are available in the [manual](https://docs.mongodb.com/manual/indexes). Morphia will apply any indexes for you at start up by
+setting the `morphia.apply-indexes` to true in the [configuration file](/configuration).
+
+There are two ways to define indexes: at the class level and at the field level.
+
+### Class Level Indexes
+
+Class level indexing begins with the [@Indexes](/javadoc/dev/morphia/annotations/Indexes.html) annotation.
+This is a container annotation whose sole purpose is to hold a number of [@Index](/javadoc/dev/morphia/annotations/Index.html) annotations.
+This annotation has two primary components to cover here: `fields` and `options`.
+An index definition would take the following form:
+
+```java
+@Entity
+@Indexes({
+ @Index(fields = @Field(value = "field2", type = DESC)),
+ @Index(
+ fields = @Field("field3"),
+ options = @IndexOptions(name = "indexing_test")
+ )
+})
+public class IndexExample {
+ @Id
+ private ObjectId id;
+ private String field;
+ @Property
+ private String field2;
+ @Property("f3")
+ private String field3;
+}
+```
+
+### Fields
+
+Which fields to index are defined with the [@Field](/javadoc/dev/morphia/annotations/Field.html) annotation.
+An arbitrary number of [@Field](/javadoc/dev/morphia/annotations/Field.html)s can be given but at least one must be present.
+The name used for the field can be either the Java field name or the mapped document field name as defined in the class's mapping via, e.g., the
+[@Property](/javadoc/dev/morphia/annotations/Property.html) or [@Embedded](/javadoc/dev/morphia/annotations/Embedded.html)
+annotations.
+For most index types, this value is validated by default.
+An exception is made for [text indexing](#text-indexing) as discussed below.
+
+### Index Options
+
+Options for an index are defined on the [@IndexOptions](/javadoc/dev/morphia/annotations/IndexOptions.html).
+More complete documentation can be found in the [manual](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#options).
+Using the options allows you to run indexing in the background, e.g. By default, creating an index blocks all other operations on a database.
+When building an index on a collection, the database that holds the collection is unavailable for read or write operations until the index build completes.
+For potentially long running index building operations, consider the **background** operation so that the MongoDB database remains available during the index building operation.
+The MongoDB [manual](https://docs.mongodb.com/manual/core/index-creation/#background-construction) has more detail.
+
+By default Morphia will attempt to validate the fields specified but in some cases that isn't desirable so you can turn it off via the options reference. `IndexOptions` lets you define [TTL](https://docs.mongodb.com/manual/core/index-ttl/), [sparse](https://docs.mongodb.com/manual/core/index-sparse/), and [partial](https://docs.mongodb.com/manual/core/index-partial/) indexes as well. `IndexOptions` can also be used to give an index a more human friendly name.
+
+{{% notice note %}}
+Whether user specified or MongoDB generated, index names including their full namespace (i.e. database.collection) cannot be longer than the [Index Name Limit](https://docs.mongodb.com/manual/reference/limits/#Index-Name-Length).
+{{% /notice %}}
+
+#### Partial Indexes
+
+New in MongoDB 3.2, [partial indexes](https://docs.mongodb.com/v3.2/core/index-partial/) only index the documents in a collection that meet a specified filter expression thereby reducing storage and maintenance costs.
+A partial filter is defined using a query as shown here:
+
+```java
+@Indexes({@Index(options =
+ @IndexOptions(partialFilter = "{ name : { $exists : true } }"),
+ fields = {@Field(value = "name")})})
+public class SomeClass {
+ ...
+}
+```
+
+## Field Level Indexes
+
+Field level indexing is a simpler approach to defining a basic, single key index.
+These indexes are defined by applying the
+[@Indexed](/javadoc/dev/morphia/annotations/Indexed.html) annotation to a particular field on a class.
+Because the index definition is applied at the field level, the index is created using only that field and so the [@Field](/javadoc/dev/morphia/annotations/Field.html)
+annotations are unnecessary.
+The options for the index are the same as defined [above](#index-options).
+A field level index definition would look like this:
+
+```java
+@Entity
+private class FieldIndex {
+ @Id
+ private ObjectId id;
+ @Indexed(options = @IndexOptions(unique = true))
+ private String name;
+ private String color;
+}
+```
+
+## Text Indexing {#text-indexing}
+
+Morphia's indexing supports MongoDB's text indexing and search functionality as we've briefly seen above.
+Full details can be found in the [manual](https://docs.mongodb.com/manual/core/index-text/) but there are a few Morphia specific details to cover.
+Indexed field names are validated by default but validation is disabled when an index is defined using MongoDB's
+[$**](https://docs.mongodb.com/manual/core/index-text/#text-index-wildcard) syntax.
+This special instruction tells MongoDB to create a text index on all fields with string content in a document.
+A [compound index](https://docs.mongodb.com/manual/core/index-text/#compound-index) can be created incorporating a text index but it's important to note there can only be one text index on a collection.
+
+A wild card text index declaration would look like this:
+
+```java
+ @Indexes(@Index(fields = @Field(value = "$**", type = TEXT)))
+```
+
+{{% notice note %}}
+A collection can have at most one text index.
+{{% /notice %}}
+
+### Collation
+
+Collation allows users to specify language-specific rules for string comparison such as rules for lettercase and accent marks.
+A collation can be defined using the `collation()` property on [@IndexOptions](/javadoc/dev/morphia/annotations/IndexOptions.html)
+and takes a [@Collation](/javadoc/dev/morphia/annotations/Collation.html) instance.
diff --git a/docs/content/features/kotlin.md b/docs/content/features/kotlin.md
new file mode 100644
index 00000000000..50913372e3b
--- /dev/null
+++ b/docs/content/features/kotlin.md
@@ -0,0 +1,42 @@
+---
+title: "Kotlin"
+weight: 2
+description: "Using Morphia with Kotlin including support for delegated properties"
+---
+
+## Kotlin
+
+In general, your Kotlin types should work out of the box with Morphia.
+There are, however, a few interesting cases where they need a little extra help.
+Morphia 2.2 introduces a new module dependency for those who need that extra support.
+To import the new
+`morphia-kotlin` module in maven, simply add this to your `pom.xml`:
+
+```xml
+
+
+ dev.morphia.morphia
+ morphia-kotlin
+ {version}
+
+
+```
+
+And, of course, gradle users can use the following dependency declaration:
+
+```groovy
+dependencies {
+ compile 'dev.morphia.morphia:morphia-kotlin:{version}'
+}
+```
+
+Explicit Kotlin support is relatively new so there are likely cases that haven't been discovered yet that might still need specific help but this new module will help cover those cases going forward.
+
+New to 2.2 is support for [delegated properties](https://kotlinlang.org/docs/delegated-properties.html).
+If your project uses
+`Delegates.notNull()`, e.g., you will want to include this module to support that delegation.
+This module should support any
+`ReadWriteProperty` type but is only currently tested against the `notNull()` case.
+
+All that is needed to enable this more targeted support is to simply add the new dependency to your project as shown above and it should magically "Just Work™".
+If you find something that doesn't work in your Kotlin project, please file an [issue](/issues-help).
diff --git a/docs/content/features/lifecycle-methods.md b/docs/content/features/lifecycle-methods.md
new file mode 100644
index 00000000000..3cbe10eef22
--- /dev/null
+++ b/docs/content/features/lifecycle-methods.md
@@ -0,0 +1,70 @@
+---
+title: "Life Cycle Methods"
+weight: 13
+description: "Use lifecycle annotations to register callbacks on Pre/Post-Persist, Save, and Load events in Morphia"
+---
+
+## Life Cycle Methods
+
+There are various annotations which can be used to register callbacks on certain life cycle events.
+These include Pre/Post-Persist (Save), and Pre/Post-Load.
+
+1. `@PrePersist` - Called before save, it can return a `Document` in place of an empty one.
+2. `@PostPersist` - Called after the save call to the database
+3. `@PreLoad` - Called before mapping the document from the database to the entity; the Document is passed as an argument (you can add/remove/change values)
+4. `@PostLoad` - Called after populating the entity with the values from the document
+
+### Examples
+
+[Here](https://github.com/MorphiaOrg/morphia/blob/master/morphia/src/test/java/dev/morphia/TestQuery.java) is a one of the test classes.
+
+All parameters and return values are options in your implemented methods.
+
+#### Example
+
+Here is a simple example of an entity that always saves the Date it was last updated.
+Alternatively, the resulting serialized form can be passed back in just prior to sending the document to the database.
+
+```java
+class BankAccount {
+ @Id
+ String id;
+ Date lastUpdated = new Date();
+
+ @PrePersist
+ public void trackUpdate() {
+ lastUpdated = new Date();
+ }
+
+ @PrePersist
+ public void prePersist( Document document) {
+ // perform operations on serialized form of the entity
+ }
+}
+```
+
+### EntityListeners
+
+If your application has more generalized life cycle events, these methods can be stored on classes external to your model.
+For example's sake, let's assume there's a need to digitally sign all documents before storing it in the database.
+
+```java
+@EntityListeners(DigitalSigner.class)
+public class BankAccount {
+ @Id
+ String id;
+ Date lastUpdated = new Date();
+}
+
+class DigitalSigner {
+ @PrePersist
+ void prePersist( Object entity, Document document) {
+ document.put("signature", sign(document));
+ }
+
+}
+```
+
+{{% notice note %}}
+**No Delete Support** Because deletes are usually done with queries there is no way to support a Delete lifecycle event.
+{{% /notice %}}
diff --git a/docs/content/features/mapping.md b/docs/content/features/mapping.md
new file mode 100644
index 00000000000..3448436d1e7
--- /dev/null
+++ b/docs/content/features/mapping.md
@@ -0,0 +1,178 @@
+---
+title: "Mapping"
+weight: 3
+description: "Learn how to map Java classes to MongoDB documents using Morphia annotations and configuration options"
+---
+
+## Mapping
+
+### Classes
+
+Mapping is triggered by annotating your type with the [@Entity](/javadoc/dev/morphia/annotations/Entity.html) annotation. This instructs Morphia to inspect your type compute various metadata items about it. If you wish use a particular type as "top level" type, you will need to annotate one field with the [@Id](/javadoc/dev/morphia/annotations/Id.html) annotation. Not every type will need to serve as a top level type (read: be mapped to a collection) and so this ID field is optional with the caveat mentioned in the call out note below. Top level types have their own collections whose names can be mapped via the `value` parameter. Leaving this value blank will leave Morphia free to compute the collection name as defined by the collection naming strategy defined in [MapperOptions](/javadoc/dev/morphia/mapping/MapperOptions.html). That default is currently the camel case value of the class's simple name. For example, to map a `UserProfile` entity under this strategy, the collection name would be mapped to `userProfile`.
+
+Any type annotated with [@Entity](/javadoc/dev/morphia/annotations/Entity.html) may optionally have a field annotated with [@Id](/javadoc/dev/morphia/annotations/Id.html). The type of the field can be any type so long as Morphia, or the driver, has a codec that can map the data to and from mongodb. When mapping an entity, one can also define [indexes](/features/indexing/) and [schema validations](/features/schemaValidation/) as part of the entity declaration as well.
+
+{{% notice note %}}
+As of 2.2, [@Embedded](/javadoc/dev/morphia/annotations/Embedded.html) has been deprecated in favor of [@Entity](/javadoc/dev/morphia/annotations/Entity.html). The distinction between the two annotations has been, historically, much more significant than it is at present. Due to the confusion about when to use which annotation and the meaning of "embedded" in general, it is being decommissioned. The two annotations have grown to mean essentially the same thing and so have become increasingly redundant.
+{{% /notice %}}
+
+{{% notice warning %}}
+Entities annotated with [@Entity](/javadoc/dev/morphia/annotations/Entity.html) that lack an [@Id](/javadoc/dev/morphia/annotations/Id.html) are not eligible to serve as "top level" types. This means they will not be mapped to a collection nor can they serve as the basis for querying or be saved directly (only as fields on top level types). ID fields are used to perform proper updates on previously persisted entities. Without that ID Morphia, can not properly restrict the update to the correct document in the database.
+{{% /notice %}}
+
+#### Constructors
+
+Morphia has traditionally required a 0-argument constructor on any mapped entity.
+In fact, Morphia still prefers to use such a constructor should one be available.
+However, as of 2.1, Morphia can also make use of another constructor that meets certain criteria:
+
+1. The number of arguments in the constructor must match the number of fields on the class.
+That is, every field must be represented in the constructor signature.
+2. The names of the arguments must match the names of the fields.
+Here, there is a bit of flexibility.
+The argument name can match either the field name as found in the source or the mapped name as determined by any `@Property` annotation.
+While this is likely to be the most common case as it is the simplest, for various this won't always be possible or preferable.
+If a constructor argument name can't mirror the field name, using the [@Name](/javadoc/dev/morphia/annotations/Name.html) annotation,
+an explicit name can be given so that the argument can be properly matched to a field.
+
+{{% notice warning %}}
+Changing the mapping configuration can interfere with Morphia's ability to map arguments and fields so be careful when making changes to such things as the default field naming strategy or [@Property](/javadoc/dev/morphia/annotations/Property.html) definitions.
+{{% /notice %}}
+
+For this mapping to take place, the source must be compiled to include the parameters in the generated bytecode.
+With `javac` this is typically already configured by default.
+However, Kotlin users will likely need to configure their builds to include the appropriate option.
+For maven users, it's as simple as adding one line to the Kotlin maven plugin ``:
+
+```xml
+ true
+```
+
+### External types
+
+Sometimes persisted types come from external libraries whose source is either unavailable or simply can't be modified.
+Using these types would be impossible give then annotation requirements as stated above.
+Morphia 2.3 introduces a new experimental API that loosens these restrictions a bit.
+Using [@ExternalEntity](/javadoc/dev/morphia/annotations/ExternalEntity.html) these external types can be mapped using a proxy type.
+
+Consider the following two types.
+This first type is an external entity which, for whatever reason, can not be annotated with Morphia's annotations.
+
+```java
+public class ThirdPartyEntity {
+ public String field;
+ public Long number;
+
+ // other methods
+
+ @Override
+ public int hashCode() {
+ // ...
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ // ...
+ }
+}
+```
+
+This class could contain any amount of other code but what we're interested in is mapping those two fields.
+To accomplish this, we define a mix-in type:
+
+```java
+@ExternalEntity(value = "extEnt",
+ discriminator = "ext",
+ discriminatorKey = "_xt",
+ concern = "JOURNALED",
+ cap = @CappedAt(count = 123, value = 456),
+ target = ThirdPartyEntity.class)
+public class ThirdPartyEntityMixIn {
+ public String field;
+ @Id
+ public Long number;
+}
+```
+
+Here you'll note the use of the new annotation. `ExternalEntity` looks just like [Entity](/javadoc/dev/morphia/annotations/Entity.html)
+but has a new field called `targetType`.
+As you can see here, we list the target type as our original `ThirdPartyEntity`.
+But this mix-in type otherwise looks just like the external type we're trying to map.
+Annotations can be applied to the fields and methods on the mix-in types and those values will be applied to the mapping data as normal.
+Using this approach, we can define alternate names for fields and map collection names, etc., as if we owned the original type all without touching it.
+As with all top level entities, if you want to store this type in its own collection, you'll need to mark a field as the ID field.
+But once this mapping is done, you can then query against the original type just as you would any other Morphia entity.
+The mix-in type can happily be ignored once you're done with mapping.
+
+{{% notice note %}}
+This API is experimental and is likely to shift a bit as it sees usage and feedback from the community.
+{{% /notice %}}
+
+### Versioning
+
+Entities can be versioned to ensure that changes are applied serially and that no other processes are modifying an object in between the time it's fetched, modified, and written back to the database.
+To achieve this, simply add a field to a type, it can be a `long` or a
+`Long`, and annotate that field with [@Version](/javadoc/dev/morphia/annotations/Version.html).
+Morphia will take care of the rest.
+If an object is fetched and another process updates the corresponding document in the database before it can be persisted back, an exception will be thrown when the write is attempted.
+
+{{% notice note %}}
+This field must not be initialized to anything other than zero or null or the ID field must be null.
+Morphia checks the value of the version field or that the ID is null in order properly save the first version.
+If neither of these conditions are true, the entity will not be persisted.
+{{% /notice %}}
+
+### Fields
+
+By default, any non-static field on a mapped class will be processed for persistence.
+If a field is to be excluded from the mapping, it can be decorated with the `transient` keyword, annotated with
+[@Transient](/javadoc/dev/morphia/annotations/Transient.html), or with the `java.beans.Transient` annotation.
+Otherwise all fields will be included that are defined on the mapped class and any super type.
+However, Morphia will ignore fields in any super types found in `java*` packages which includes the standard JDK classes and the Java EE APIs.
+
+There are times when it is necessary to modify a field mapping's name, e.g. Using the
+[@Property](/javadoc/dev/morphia/annotations/Property.html) annotation, a new name can be defined that will be used when writing to and reading from the database.
+During a schema evolution, it is possible to load a field from an old name as well using the
+[@AlsoLoad](/javadoc/dev/morphia/annotations/AlsoLoad.html) annotation.
+Using this annotation, multiple old names can be used to find a field's value in a returned document from query.
+However, only the field's name or the value specified in the `@Property` annotation will be used when writing documents back to the database.
+Similarly, if data is only intended to be loaded from the database but never written back, that field can be annotated with [@LoadOnly](/javadoc/dev/morphia/annotations/LoadOnly.html)
+
+If you do not specify a name via `@Property`, the default field naming strategy will be used.
+The default strategy is to use the field's name as defined in the source.
+This strategy can be changed globally via the field naming strategy option on
+[MapperOptions](/javadoc/dev/morphia/mapping/MapperOptions.html).
+Simple indexes can be defined on a field if all that is needed for the index is a single field.
+This can be done via the [@Indexed](/javadoc/dev/morphia/annotations/Indexed.html) annotation.
+
+### Methods
+
+{{% notice warning %}}
+Method-based mapping is new in 2.2. While testing has been done to ensure everything works the same as with fields, there may some esoteric combinations of features that reveal a gap in functionality.
+Please file an [issue](https://github.com/MorphiaOrg/morphia/issues)
+if you encounter such a case.
+{{% /notice %}}
+
+As of 2.2, mapping information can be defined on methods instead of fields.
+All the same rules apply, simply the location of the annotations are moved to the getters and/or setters. Annotations can live on either the `get` or the `set` method and Morphia will detect them.
+If the same annotation is applied to both the `get` and the `set` behavior is unpredictable so care should be taken to avoid such a scenario.
+Customs in other libraries tend to favor annotating the `get` methods and this is also recommended here for consistency.
+
+In order for methods to be considered as definitions of persistable properties, the Java Bean Spec largely applies here.
+This has some very basic rules for your methods:
+
+1. `get` methods take no parameters
+2. `set` methods take one parameter and the type of that parameter should generally match the return type of the getter. These setter methods also return void.
+3. If a property is a boolean type, the getter often uses `is` rather than `get` yielding a method named, e.g., `isEnabled()` rather than
+`getEnabled()`.
+4. The type of the property is determined by the return value of the getter.
+5. The name of the property is determined by stripping the `get` prefix (or `is` for boolean types) and lower casing the first letter.
+This is the default name of the property subject to property naming rules as defined in
+[MapperOptions](/javadoc/dev/morphia/mapping/MapperOptions.html)
+
+To enable method mapping, a method has been added to [MapperOptions.Builder](/javadoc/dev/morphia/mapping/MapperOptions.Builder.html)
+allowing for the configuration of either field or method mapping.
+
+{{% notice note %}}
+Mapping is currently done via either fields or by methods. It is not currently allowed to map using both schemes simultaneously. This will likely change in the future but for now is not allowed.
+{{% /notice %}}
diff --git a/docs/content/features/queries.md b/docs/content/features/queries.md
new file mode 100644
index 00000000000..d12724471d1
--- /dev/null
+++ b/docs/content/features/queries.md
@@ -0,0 +1,223 @@
+---
+title: "Queries"
+weight: 6
+description: "Learn how to build queries in Morphia to find and filter documents with type-safe operations"
+---
+
+## Queries
+
+Morphia provides [Query](/javadoc/dev/morphia/query/Query.html) class to build a query and map the results back to instances of your entity classes and attempts to provide as much type safety and validation as possible.
+To create the `Query`, we invoke the following code:
+
+```java
+Query query = datastore.find(Product.class);
+```
+
+`find()` returns an instance of `Query` which we can use to build a query.
+
+### `filter()`
+
+The most significant method `filter(Filter...)`.
+This method takes a number of filters to apply to the query being built.
+The filters are added to any existing, previously defined filters so you needn't add them all at once.
+There are dozens of filters predefined in Morphia and can be found in the `dev.morphia.query.filters` package. You can find the full
+list in the [Supported Operators](#supported-operators) section.
+
+The filters can be accessed via the [Filters](/javadoc/dev/morphia/query/filters/Filters.html) class.
+The method names largely match the operation name you would use querying via the mongo shell so this should help you translate queries in to Morphia's API.
+For example, to query for products whose prices is greater than or equal to 1000, you would write this:
+
+```java
+query.filter(Filters.gte("price", 1000));
+```
+
+This will append the new criteria to any existing criteria already defined.
+You can define as many filters in one call as you'd like or you may choose to append them in smaller groups based on whatever query building logic your application might have.
+
+### Complex Queries
+
+Of course, queries are usually more complex than single field comparisons.
+Morphia offers both `and()` and `or()` to build up more complex queries.
+An `and` query might look something like this:
+
+```java
+q.filter(and(
+ eq("width", 10),
+ eq("height", 1)));
+```
+
+An `or` clause looks exactly the same except for using `or()` instead of `and()`, of course.
+The default is to "and" filter criteria together so if all you need is an `and` clause, you don't need an explicit call to `and()`:
+
+```java
+datastore.find(UserLocation.class)
+ .filter(
+ lt("x", 5),
+ gt("y", 4),
+ gt("z", 10));
+```
+
+This generates an implicit `and` across the field comparisons.
+
+## Other Query Options
+
+There is more to querying than simply filtering against different document values.
+Listed below are some of the options for modifying the query results in different ways.
+
+### Projections
+
+[Projections](https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/) allow you to return only a subset of the fields in a document.
+This is useful when you need to only return a smaller view of a larger object.
+Borrowing from the
+[unit tests](https://github.com/MorphiaOrg/morphia/blob/master/morphia/src/test/java/dev/morphia/TestQuery.java), this is an example of this feature in action:
+
+```java
+ContainsRenamedFields user = new ContainsRenamedFields("Frank", "Zappa");
+datastore.save(user);
+
+ContainsRenamedFields found = datastore
+ .find(ContainsRenamedFields.class)
+ .iterator(new FindOptions()
+ .projection().include("first_name")
+ .limit(1))
+ .tryNext();
+assertNotNull(found.firstName);
+assertNull(found.lastName);
+```
+
+As you can see here, we're saving this entity with a first and last name but our query only returns the first name (and the `_id` value) in the returned instance of our type.
+It's also worth noting that this projection works with both the mapped document field name
+`"first_name"` and the Java field name `"firstName"`.
+
+{{% notice warning %}}
+While projections can be a nice performance win in some cases, it's important to note that this object can not be safely saved back to MongoDB. Any fields in the existing document in the database that are missing from the entity will be removed if this entity is saved.
+For example, in the example above if `found` is saved back to MongoDB, the `last_name` field that currently exists in the database for this entity will be removed.
+To save such instances back consider using
+[Datastore#merge(T)](/javadoc/dev/morphia/Datastore.html#merge(T))
+{{% /notice %}}
+
+### Limiting and Skipping
+
+Pagination of query results is often done as a combination of skips and limits.
+Morphia offers `FindOptions.limit(int)` and
+`FindOptions.skip(int)` for these cases.
+An example of these methods in action would look like this:
+
+```java
+datastore.find(Person.class)
+ .iterator(new FindOptions()
+ .skip(1)
+ .limit(10))
+```
+
+This query will skip the first element and take up to the next 10 items found by the query.
+There's a caveat to using skip/limit for pagination, however.
+See the [skip](https://docs.mongodb.com/manual/reference/method/cursor.skip) documentation for more detail.
+
+### Ordering
+
+Ordering the results of a query is done via
+[FindOptions.sort(Sort...)](/javadoc/dev/morphia/query/FindOptions.html#sort(dev.morphia.query.Sort...)), etc.
+For example, to sort by `age` (youngest to oldest) and then `income` (highest to lowest), you would use this:
+
+```java
+getDs().find(User.class)
+ .iterator(new FindOptions()
+ .sort(ascending("age"), descending("income"))
+ .limit(1))
+ .tryNext();
+```
+
+### Tailable Cursors
+
+If you have a [capped collection](https://docs.mongodb.com/manual/core/capped-collections/) it's possible to "tail" a query so that when new documents are added to the collection that match your query, they'll be returned by the
+[tailable cursor](https://docs.mongodb.com/manual/reference/glossary/#term-tailable-cursor).
+An example of this feature in action can be found in the
+[unit tests](https://github.com/MorphiaOrg/morphia/blob/master/morphia/src/test/java/dev/morphia/TestQuery.java) in the `testTailableCursors()` test:
+
+```java
+datastore.getMapper().map(CappedPic.class);
+getDs().ensureCaps(); // <1>
+final Query query = getDs().find(CappedPic.class);
+final List found = new ArrayList<>();
+
+final MorphiaCursor tail =
+ query.iterator(new FindOptions()
+ .cursorType(CursorType.Tailable));
+while(found.size() < 10) {
+ found.add(tail.next()); // <2>
+}
+```
+
+There are two things to note about this code sample:
+
+1. This tells Morphia to make sure that any entity configured to use a capped collection has its collection created correctly.
+If the collection already exists and is not capped, you will have to manually
+[update](https://docs.mongodb.com/manual/core/capped-collections/#convert-a-collection-to-capped) your collection to be a capped collection.
+2. Since this `Iterator` is backed by a tailable cursor, `hasNext()` and `next()` will block until a new item is found.
+In this version of the unit test, we tail the cursor waiting to pull out objects until we have 10 of them and then proceed with the rest of the application.
+
+### Polymorphic Queries
+
+By default, Morphia will only return documents of the type given in `find()`. However, if you want to retrieve subtypes as well, you can
+enable this in `MorphiaConfig` via
+[MorphiaConfig#enablePolymorphicQueries()](/javadoc/dev/morphia/config/MorphiaConfig.html#enablePolymorphicQueries()).
+
+{{% notice note %}}
+Queries by ID will ignore this setting since such queries are filtering by a specific, unique value and polymorphic queries do incur
+potential performance hits due to the wider scope of the query filter.
+{{% /notice %}}
+
+### Supported Operators
+Every effort is made to provide 100% coverage of all the operators offered by MongoDB. Below is listed all the currently supported
+operators. To see an example of an operator in action, click through to see the test cases for that operator.
+
+If an operator is missing and you think it should be included, please file an [issue](https://github.com/MorphiaOrg/morphia/issues) for that operator.
+
+#### Filters
+
+| Operator | Docs | Test Examples |
+|----------|------|---------------|
+| [$all](http://docs.mongodb.org/manual/reference/operator/query/all) | [Filters#all(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#all(java.lang.String,java.lang.Object)) | [TestAll](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestAll.java) |
+| [$and](http://docs.mongodb.org/manual/reference/operator/query/and) | [Filters#and(Filter...)](/javadoc/dev/morphia/query/filters/Filters.html#and(dev.morphia.query.filters.Filter...)) | [TestAnd](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestAnd.java) |
+| [$bitsAllClear](http://docs.mongodb.org/manual/reference/operator/query/bitsAllClear) | [Filters#bitsAllClear(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#bitsAllClear(java.lang.String,java.lang.Object)) | [TestBitsAllClear](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestBitsAllClear.java) |
+| [$bitsAllSet](http://docs.mongodb.org/manual/reference/operator/query/bitsAllSet) | [Filters#bitsAllSet(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#bitsAllSet(java.lang.String,java.lang.Object)) | [TestBitsAllSet](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestBitsAllSet.java) |
+| [$bitsAnyClear](http://docs.mongodb.org/manual/reference/operator/query/bitsAnyClear) | [Filters#bitsAnyClear(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#bitsAnyClear(java.lang.String,java.lang.Object)) | [TestBitsAnyClear](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestBitsAnyClear.java) |
+| [$bitsAnySet](http://docs.mongodb.org/manual/reference/operator/query/bitsAnySet) | [Filters#bitsAnySet(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#bitsAnySet(java.lang.String,java.lang.Object)) | [TestBitsAnySet](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestBitsAnySet.java) |
+| [$box](http://docs.mongodb.org/manual/reference/operator/query/box) | [Filters#box(String,Point,Point)](/javadoc/dev/morphia/query/filters/Filters.html#box(java.lang.String,com.mongodb.client.model.geojson.Point,com.mongodb.client.model.geojson.Point)) | [TestBox](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestBox.java) |
+| [$center](http://docs.mongodb.org/manual/reference/operator/query/center) | [Filters#center(String,Point,double)](/javadoc/dev/morphia/query/filters/Filters.html#center(java.lang.String,com.mongodb.client.model.geojson.Point,double)) | [TestCenter](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestCenter.java) |
+| [$centerSphere](http://docs.mongodb.org/manual/reference/operator/query/centerSphere) | [Filters#centerSphere(String,Point,double)](/javadoc/dev/morphia/query/filters/Filters.html#centerSphere(java.lang.String,com.mongodb.client.model.geojson.Point,double)) | [TestCenterSphere](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestCenterSphere.java) |
+| [$comment](http://docs.mongodb.org/manual/reference/operator/query/comment) | [Filters#comment(String)](/javadoc/dev/morphia/query/filters/Filters.html#comment(java.lang.String)) | [TestComment](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestComment.java) |
+| [$elemMatch](http://docs.mongodb.org/manual/reference/operator/query/elemMatch) | [Filters#elemMatch(Filter...)](/javadoc/dev/morphia/query/filters/Filters.html#elemMatch(dev.morphia.query.filters.Filter...)) [Filters#elemMatch(String,Filter...)](/javadoc/dev/morphia/query/filters/Filters.html#elemMatch(java.lang.String,dev.morphia.query.filters.Filter...)) | [TestElemMatch](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestElemMatch.java) |
+| [$eq](http://docs.mongodb.org/manual/reference/operator/query/eq) | [Filters#eq(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#eq(java.lang.String,java.lang.Object)) | [TestEq](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestEq.java) |
+| [$exists](http://docs.mongodb.org/manual/reference/operator/query/exists) | [Filters#exists(String)](/javadoc/dev/morphia/query/filters/Filters.html#exists(java.lang.String)) | [TestExists](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestExists.java) |
+| [$expr](http://docs.mongodb.org/manual/reference/operator/query/expr) | [Filters#expr(Expression)](/javadoc/dev/morphia/query/filters/Filters.html#expr(dev.morphia.aggregation.expressions.impls.Expression)) | [TestExpr](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestExpr.java) |
+| [$geoIntersects](http://docs.mongodb.org/manual/reference/operator/query/geoIntersects) | [Filters#geoIntersects(String,Geometry)](/javadoc/dev/morphia/query/filters/Filters.html#geoIntersects(java.lang.String,com.mongodb.client.model.geojson.Geometry)) | [TestGeoIntersects](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestGeoIntersects.java) |
+| [$geoWithin](http://docs.mongodb.org/manual/reference/operator/query/geoWithin) | [Filters#geoWithin(String,Polygon)](/javadoc/dev/morphia/query/filters/Filters.html#geoWithin(java.lang.String,com.mongodb.client.model.geojson.Polygon)) [Filters#geoWithin(String,MultiPolygon)](/javadoc/dev/morphia/query/filters/Filters.html#geoWithin(java.lang.String,com.mongodb.client.model.geojson.MultiPolygon)) | [TestGeoWithin](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestGeoWithin.java) |
+| [$geometry](http://docs.mongodb.org/manual/reference/operator/query/geometry) | [Filters#geometry(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#geometry(java.lang.String,java.lang.Object)) | [TestGeometry](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestGeometry.java) |
+| [$gt](http://docs.mongodb.org/manual/reference/operator/query/gt) | [Filters#gt(Object)](/javadoc/dev/morphia/query/filters/Filters.html#gt(java.lang.Object)) [Filters#gt(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#gt(java.lang.String,java.lang.Object)) | [TestGt](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestGt.java) |
+| [$gte](http://docs.mongodb.org/manual/reference/operator/query/gte) | [Filters#gte(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#gte(java.lang.String,java.lang.Object)) [Filters#gte(Object)](/javadoc/dev/morphia/query/filters/Filters.html#gte(java.lang.Object)) | [TestGte](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestGte.java) |
+| [$in](http://docs.mongodb.org/manual/reference/operator/query/in) | [Filters#in(String,Iterable)](/javadoc/dev/morphia/query/filters/Filters.html#in(java.lang.String,java.lang.Iterable)) [Filters#in(Iterable)](/javadoc/dev/morphia/query/filters/Filters.html#in(java.lang.Iterable)) | [TestIn](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestIn.java) |
+| [$jsonSchema](http://docs.mongodb.org/manual/reference/operator/query/jsonSchema) | [Filters#jsonSchema(Document)](/javadoc/dev/morphia/query/filters/Filters.html#jsonSchema(org.bson.Document)) | [TestJsonSchema](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestJsonSchema.java) |
+| [$lt](http://docs.mongodb.org/manual/reference/operator/query/lt) | [Filters#lt(Object)](/javadoc/dev/morphia/query/filters/Filters.html#lt(java.lang.Object)) [Filters#lt(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#lt(java.lang.String,java.lang.Object)) | [TestLt](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestLt.java) |
+| [$lte](http://docs.mongodb.org/manual/reference/operator/query/lte) | [Filters#lte(Object)](/javadoc/dev/morphia/query/filters/Filters.html#lte(java.lang.Object)) [Filters#lte(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#lte(java.lang.String,java.lang.Object)) | [TestLte](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestLte.java) |
+| [$maxDistance](http://docs.mongodb.org/manual/reference/operator/query/maxDistance) | [Filters#maxDistance(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#maxDistance(java.lang.String,java.lang.Object)) | [TestMaxDistance](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestMaxDistance.java) |
+| [$meta](http://docs.mongodb.org/manual/reference/operator/query/meta) | [Meta#indexKey(String)](/javadoc/dev/morphia/query/Meta.html#indexKey(java.lang.String)) [Meta#searchHighlights(String)](/javadoc/dev/morphia/query/Meta.html#searchHighlights(java.lang.String)) [Meta#searchScore(String)](/javadoc/dev/morphia/query/Meta.html#searchScore(java.lang.String)) [Meta#textScore(String)](/javadoc/dev/morphia/query/Meta.html#textScore(java.lang.String)) | [TestMeta](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestMeta.java) |
+| [$minDistance](http://docs.mongodb.org/manual/reference/operator/query/minDistance) | [Filters#minDistance(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#minDistance(java.lang.String,java.lang.Object)) | [TestMinDistance](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestMinDistance.java) |
+| [$mod](http://docs.mongodb.org/manual/reference/operator/query/mod) | [Filters#mod(String,long,long)](/javadoc/dev/morphia/query/filters/Filters.html#mod(java.lang.String,long,long)) [Filters#mod(String,double,double)](/javadoc/dev/morphia/query/filters/Filters.html#mod(java.lang.String,double,double)) | [TestMod](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestMod.java) |
+| [$natural](http://docs.mongodb.org/manual/reference/operator/query/natural) | [Sort#naturalAscending()](/javadoc/dev/morphia/query/Sort.html#naturalAscending()) [Sort#naturalDescending()](/javadoc/dev/morphia/query/Sort.html#naturalDescending()) | [TestNatural](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestNatural.java) |
+| [$ne](http://docs.mongodb.org/manual/reference/operator/query/ne) | [Filters#ne(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#ne(java.lang.String,java.lang.Object)) | [TestNe](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestNe.java) |
+| [$near](http://docs.mongodb.org/manual/reference/operator/query/near) | [Filters#near(String,Point)](/javadoc/dev/morphia/query/filters/Filters.html#near(java.lang.String,com.mongodb.client.model.geojson.Point)) | [TestNear](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestNear.java) |
+| [$nearSphere](http://docs.mongodb.org/manual/reference/operator/query/nearSphere) | [Filters#nearSphere(String,Point)](/javadoc/dev/morphia/query/filters/Filters.html#nearSphere(java.lang.String,com.mongodb.client.model.geojson.Point)) | [TestNearSphere](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestNearSphere.java) |
+| [$nin](http://docs.mongodb.org/manual/reference/operator/query/nin) | [Filters#nin(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#nin(java.lang.String,java.lang.Object)) | [TestNin](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestNin.java) |
+| [$nor](http://docs.mongodb.org/manual/reference/operator/query/nor) | [Filters#nor(Filter...)](/javadoc/dev/morphia/query/filters/Filters.html#nor(dev.morphia.query.filters.Filter...)) | [TestNor](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestNor.java) |
+| [$not](http://docs.mongodb.org/manual/reference/operator/query/not) | [Filter#not()](/javadoc/dev/morphia/query/filters/Filter.html#not()) | [TestNot](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestNot.java) |
+| [$or](http://docs.mongodb.org/manual/reference/operator/query/or) | [Filters#or(Filter...)](/javadoc/dev/morphia/query/filters/Filters.html#or(dev.morphia.query.filters.Filter...)) | [TestOr](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestOr.java) |
+| [$polygon](http://docs.mongodb.org/manual/reference/operator/query/polygon) | [Filters#polygon(String,Point...)](/javadoc/dev/morphia/query/filters/Filters.html#polygon(java.lang.String,com.mongodb.client.model.geojson.Point...)) | [TestPolygon](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestPolygon.java) |
+| [$regex](http://docs.mongodb.org/manual/reference/operator/query/regex) | [Filters#regex(String,String)](/javadoc/dev/morphia/query/filters/Filters.html#regex(java.lang.String,java.lang.String)) [Filters#regex(String,Pattern)](/javadoc/dev/morphia/query/filters/Filters.html#regex(java.lang.String,java.util.regex.Pattern)) | [TestRegex](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestRegex.java) |
+| [$size](http://docs.mongodb.org/manual/reference/operator/query/size) | [Filters#size(String,int)](/javadoc/dev/morphia/query/filters/Filters.html#size(java.lang.String,int)) | [TestSize](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestSize.java) |
+| [$slice](http://docs.mongodb.org/manual/reference/operator/query/slice) | [ArraySlice#limit(int)](/javadoc/dev/morphia/query/ArraySlice.html#limit(int)) | [TestSlice](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestSlice.java) |
+| [$text](http://docs.mongodb.org/manual/reference/operator/query/text) | [Filters#text(String)](/javadoc/dev/morphia/query/filters/Filters.html#text(java.lang.String)) | [TestText](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestText.java) |
+| [$type](http://docs.mongodb.org/manual/reference/operator/query/type) | [Filters#type(String,Type...)](/javadoc/dev/morphia/query/filters/Filters.html#type(java.lang.String,dev.morphia.query.Type...)) | [TestType](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestType.java) |
+| [$uniqueDocs](http://docs.mongodb.org/manual/reference/operator/query/uniqueDocs) | [Filters#uniqueDocs(String,Object)](/javadoc/dev/morphia/query/filters/Filters.html#uniqueDocs(java.lang.String,java.lang.Object)) | [TestUniqueDocs](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestUniqueDocs.java) |
+| [$where](http://docs.mongodb.org/manual/reference/operator/query/where) | [Filters#where(String)](/javadoc/dev/morphia/query/filters/Filters.html#where(java.lang.String)) | [TestWhere](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/filters/TestWhere.java) |
diff --git a/docs/content/features/references.md b/docs/content/features/references.md
new file mode 100644
index 00000000000..532810b9823
--- /dev/null
+++ b/docs/content/features/references.md
@@ -0,0 +1,40 @@
+---
+title: "References"
+weight: 11
+description: "Learn how to use MongoDB database references in Morphia with @Reference annotation or MorphiaReference wrapper type"
+---
+
+## References
+
+MongoDB tries to encourage self-contained documents so that data can be fetched much more efficiently via single reads from the database.
+However not every data model or application can adhere to this philosophy in its entirety.
+As such, MongoDB supports [database references](https://www.mongodb.com/docs/manual/reference/database-references/). Morphia supports two styles of defining references:
+
+1. the [@Reference](/javadoc/dev/morphia/annotations/Reference.html) annotation
+2. an experimental wrapper type [MorphiaReference](/javadoc/dev/morphia/mapping/experimental/MorphiaReference.html).
+
+### Using the annotation
+
+The annotation based approach is the traditional approach.
+The [@Reference](/javadoc/dev/morphia/annotations/Reference.html) can be applied to any property whose type is a mappable Entity type.
+When this is done, instead of storing that objects information as a subdocument in the larger document sent to the database, a reference will be stored instead which points to where the document is actually stored.
+The referenced types are stored according to the mapping information configured by their
+[@Entity](/javadoc/dev/morphia/annotations/Entity.html) annotations.
+
+{{% notice note %}}
+It can be helpful to think of references as a foreign key like you would find in a relational database.
+It's important to note, however, that MongoDB does not enforce any notion of referential integrity with these keys.
+Those remote documents may or may not actually exist and you will have to tailor your application (and configure Morphia as we'll see in a moment) to deal with those missing documents.
+{{% /notice %}}
+
+The annotation provides a number of options to help tailor Morphia's behavior to your liking.
+
+1. `idOnly` -- _defaults to false_ When `true`, only the value of the ID field is stored in the enclosing documents.
+If the referenced entity type has no subclasses, setting this can help save disk space and network traffic.
+If there *are* subtypes, this setting may be overridden automatically so that type information can properly stored.
+2. `ignoreMissing` _defaults to false_ When `true`, references that can not be loaded are simply ignored.
+Otherwise an exception is thrown whenever the reference load is attempted.
+3. `lazy` _defaults to false_ When `true` the referenced entity will not be fetched until the property is explicitly referenced.
+Otherwise the referenced entity (or entities) are loaded as part of the query load cycle of the enclosing entity.
+
+A `String` may be passed to the annotation to define the document field name to be stored in the database.
diff --git a/docs/content/features/schema-validation.md b/docs/content/features/schema-validation.md
new file mode 100644
index 00000000000..2dff493af6d
--- /dev/null
+++ b/docs/content/features/schema-validation.md
@@ -0,0 +1,34 @@
+---
+title: "Schema Validation"
+weight: 14
+description: "Define MongoDB document validations for collections alongside entity mapping data in Morphia"
+---
+
+## Schema Validation
+
+Morphia provides annotations that allow developers to define document validations for a collection to be defined alongside the other mapping data on an entity's source. [Schema validation](https://www.mongodb.com/docs/manual/core/schema-validation/) provides the capability to perform schema validation during updates and insertions.
+Validation rules are on a per-collection basis and can be defined via annotations just like indexes are. Morphia will automatically
+apply mapped document validations when `morphia.apply-document-validations` is set to true in the [configuration file](/features/configuration/).
+
+Below we have a basic entity definition.
+Note the new annotation [@Validation](/javadoc/dev/morphia/annotations/Validation.html).
+
+```java
+@Entity("validation")
+@Validation("{ number : { $gt : 10 } }")
+public class DocumentValidation {
+ @Id
+ private ObjectId id;
+ private String string;
+ private int number;
+ private Date date;
+
+}
+```
+
+In this case, only one value is supplied to the annotation.
+This string value is the query that will be used to match against any new documents or updated documents.
+Should this query fail to match the new document, validation will fail on the document and it will be rejected.
+In addition to the required query, there are two other values that can be configured based on your needs: `level` with a default of `STRICT` and `action` with a default of `ERROR`.
+A `MODERATE` validation level does not apply rules to updates on existing invalid documents.
+An `action` setting of `WARN` will merely log any validation violations.
diff --git a/docs/content/features/sharding.md b/docs/content/features/sharding.md
new file mode 100644
index 00000000000..2ebe831bb17
--- /dev/null
+++ b/docs/content/features/sharding.md
@@ -0,0 +1,73 @@
+---
+title: "Sharding"
+weight: 5
+description: "Defining and using sharded collections with Morphia"
+---
+
+## Sharding
+
+{{% notice note %}}
+Sharding support is new in 2.3 and should be considered experimental.
+While all tests currently pass, the form and function of the sharding support might change as issues arise and any usability concerns are addressed.
+This is feature is safe to use just be aware that this API might change based on user feedback.
+{{% /notice %}}
+
+Much like the indexing support, Morphia provides a number of annotations to help in the definition and use of sharded collections.
+You don't need to use Morphia to shard your collections, but if your collection is sharded, you must also define that shard key on your entity in order for Morphia to properly generate certain operations.
+
+Documentation on how to choose a proper shard key can be found in the [manual](https://www.mongodb.com/docs/manual/sharding).
+
+### Shard Definition
+
+Sharding definitions are driven by the [@ShardKeys](/javadoc/dev/morphia/annotations/ShardKeys.html) annotation.
+This annotation takes two values: the shard keys themselves as defined by the [@ShardKey](/javadoc/dev/morphia/annotations/ShardKey.html) annotation and the options to apply when sharding the collection via the [@ShardOptions](/javadoc/dev/morphia/annotations/ShardOptions.html)
+annotation.
+
+An shard definition might look something like this.
+
+```java
+@Entity("profiles")
+@ShardKeys({@ShardKey(value = "name", type = HASHED)})
+private static class UserProfiles {
+ @Id
+ private ObjectId id;
+ private final String name;
+ private String nickName;
+ private LocalDateTime date;
+}
+```
+
+In this example, we have a single property used in the shard key.
+In this case, we're making use of
+[hashed sharding](https://www.mongodb.com/docs/manual/core/hashed-sharding).
+The other type of shard key supported by MongoDB is
+[ranged sharding](https://www.mongodb.com/docs/manual/core/ranged-sharding).
+You can define that kind of shard key just like the example above except instead of
+`HASHED`, you would use `RANGED`.
+Additionally, since the default type is `RANGED`, you can omit this value entirely and simplify your definitions to `@ShardKey("price")`, for example.
+
+{{% notice note %}}
+In the example above, you'll note that the property we've defined as part of the shard key is declared as final.
+It is recommended that you follow this practice to help prevent mutating your shard key values in memory.
+If you were to fetch an entity and update one or more of the shard key properties, mongodb would be unable to find the document in the database to update with the new state.
+If you find yourself needing to mutate one of those properties, consult the [manual](https://www.mongodb.com/docs/manual/core/sharding-change-shard-key-value/) first.
+{{% /notice %}}
+
+{{% notice note %}}
+Morphia does not currently support redefining the shard key definition entirely.
+{{% /notice %}}
+
+### Sharding Options
+
+`@ShardKeys` also has an `options` field which takes a [@ShardOptions](/javadoc/dev/morphia/annotations/ShardOptions.html).
+Using this annotation, you can configure the number of initial shards, [presplit the hashed zones](https://www.mongodb.com/docs/manual/core/hashed-sharding/#shard-an-empty-collection), or [enforce uniqueness](https://www.mongodb.com/docs/manual/core/sharding-shard-key/#unique-indexes) in your shard key.
+
+### How is it used?
+
+Once you have your sharding configured, you have the choice of manually sharding it via the mongo shell or having Morphia shard it for you.
+For the latter, there is a new method [shardCollections()](/javadoc/dev/morphia/Datastore.html#shardCollections()) that will do
+this for you. It should be noted here that if your collection is not empty, there are certain administrative tasks you must perform on the collection first that Morphia does *not* handle.
+You can find those details in the server documentation.
+
+Once your collection is sharded, Morphia uses the shard key definition to update certain operations (such as saves/upserts and find-and-modify among others) to include the relevant shard key information so that mongodb can quickly and efficiently find the documents in the database.
+This is done transparently for you so you needn't worry about doing such things manually.
diff --git a/docs/content/features/text-search.md b/docs/content/features/text-search.md
new file mode 100644
index 00000000000..f74dc0f19f1
--- /dev/null
+++ b/docs/content/features/text-search.md
@@ -0,0 +1,66 @@
+---
+title: "Text Searches"
+weight: 10
+description: "Using MongoDB's text search capabilities with Morphia"
+---
+
+## Text Searches
+
+Morphia also supports MongoDB's text search capabilities.
+In order to execute a text search against a collection, the collection must have a [text index](https://www.mongodb.com/docs/manual/core/index-text/) defined first.
+Using Morphia that definition would look like this:
+
+```java
+@Indexes(@Index(fields = @Field(value = "$**", type = IndexType.TEXT)))
+public static class Greeting {
+ @Id
+ private ObjectId id;
+ private String value;
+ private String language;
+
+}
+```
+
+The `$**` value tells MongoDB to create a text index on all the text fields in a document.
+A more targeted index can be created, if desired, by explicitly listing which fields to index.
+Once the index is defined, we can start querying against it like this
+[test](https://github.com/MorphiaOrg/morphia/blob/master/legacy-tests/src/test/java/dev/morphia/query/TestTextSearching.java) does:
+
+```java
+mapper.map(Greeting.class);
+datastore.ensureIndexes();
+
+datastore.save(new Greeting("good morning", "english"),
+ new Greeting("good afternoon", "english"),
+ new Greeting("good night", "english"),
+ new Greeting("good riddance", "english"),
+ new Greeting("guten Morgen", "german"),
+ new Greeting("guten Tag", "german")),
+ new Greeting("gute Nacht", "german"));
+
+List good = getDs().find(Greeting.class)
+ .filter(text("good"))
+ .execute(new FindOptions()
+ .sort(ascending("_id")))
+ .toList();
+Assert.assertEquals(4, good.size());
+```
+
+As you can see here, we create `Greeting` objects for multiple languages.
+In our test query, we're looking for occurrences of the word "good" in any document.
+Using the method `text()` found on the `Filters` class, we can then query for all instances of our search term.
+We created four such documents and our query returns exactly those four.
+
+If you would like to restrict your search to a specific language, that can also be specified as part of the query:
+
+```java
+datastore.find(Greeting.class)
+ .filter(text("good")
+ .language("english"))
+ .execute(new FindOptions()
+ .sort(ascending("_id")))
+ .toList();
+```
+
+There are some optional parameters in addition to the language you can specify as part of your text search.
+Those parameters are documented on the [TextSearchFilter](/javadoc/dev/morphia/query/filters/TextSearchFilter.html) class.
diff --git a/docs/content/features/transactions.md b/docs/content/features/transactions.md
new file mode 100644
index 00000000000..892453e5f73
--- /dev/null
+++ b/docs/content/features/transactions.md
@@ -0,0 +1,58 @@
+---
+title: "Transactions"
+weight: 12
+description: "Use multi-document transactions in Morphia with MongoDB replica sets for atomic operations."
+---
+
+## Transactions
+
+Starting with MongoDB version 4.0, multi-document transactions are now supported on replica sets.
+Morphia 2.0 introduced a simple mechanism to access this functionality.
+Morphia 2.0 added the methods `withTransaction(MorphiaTransaction transaction)` and
+`withTransaction(ClientSessionOptions options, MorphiaTransaction transaction)` allowing for the execution of logic scoped to a transaction.
+
+The API is designed to work with Java 8's lambda syntax for the most convenience.
+In this example, let's assume we're building a shopping site.
+
+```java
+User account = datastore.withTransaction((session) -> {
+ User user = new User("jimbo", "jimhalpert@dundermifflin.com");
+ user.setHomeAddress(new Address("123 Paper Lane", "Scranton", "PA", "18510"));
+
+ return session.save(user);
+});
+```
+
+In this simple example, we're starting with our standard `Datastore` and calling `withTransaction()`.
+The lambda we're passing in executes all with the scope of a single transaction.
+You'll note the single parameter passed in is a `MorphiaSession`.
+This is actually a `Datastore` but it has been bound to a session.
+Any changes to be made within the transaction should be made using this
+`session` reference.
+Once the lambda returns, the transaction is automatically committed and the session closed.
+If you need access to server session or the transaction, there are methods on `MorphiaSession` to return either of those.
+
+Of course, it's not always possible to wrap things up neatly inside a lambda so let's take a look at more hands on approach:
+
+```java
+MorphiaSession session = datastore.startSession();
+session.startTransaction();
+User user = new User("jimbo", "jimhalpert@dundermifflin.com");
+user.setHomeAddress(new Address("123 Paper Lane", "Scranton", "PA", "18510"));
+session.save(user);
+session.commitTransaction();
+session.close();
+```
+
+This is essentially the same logic as above but now we're manually managing the transactional boundaries. `MorphiaSession` is also
+`AutoCloseable` so you could wrap the entire block in a `try-with-resources` block and let that manage the session boundary for you:
+
+```java
+try(MorphiaSession session = datastore.startSession()) {
+ session.startTransaction();
+ User user = new User("jimbo", "jimhalpert@dundermifflin.com");
+ user.setHomeAddress(new Address("123 Paper Lane", "Scranton", "PA", "18510"));
+ session.save(user);
+ session.commitTransaction();
+}
+```
diff --git a/docs/content/features/updates.md b/docs/content/features/updates.md
new file mode 100644
index 00000000000..a44cd9925b3
--- /dev/null
+++ b/docs/content/features/updates.md
@@ -0,0 +1,183 @@
+---
+title: "Updates"
+weight: 7
+description: "Learn how to update documents in Morphia using server-side operations without fetching data across the wire"
+---
+
+## Updates
+
+Updates in 2.0, are issued using a `Query` instance . These update operations are executed on the server without fetching any documents across the wire.
+Update operations are defined using a set of functions as defined on
+[UpdateOperators](/javadoc/dev/morphia/query/updates/UpdateOperators.html).
+In our examples, we'll be using the following model:
+
+```java
+@Entity("hotels")
+public class Hotel
+{
+ @Id
+ private ObjectId id;
+
+ private String name;
+ private int stars;
+
+ @Embedded
+ private Address address;
+
+ List roomNumbers = new ArrayList();
+
+ // ... getters and setters
+}
+
+@Embedded
+public class Address
+{
+ private String street;
+ private String city;
+ private String postalCode;
+ private String country;
+
+ // ... getters and setters
+}
+```
+
+### set()/unset()
+
+To change the name of the hotel, one would use something like this:
+
+```java
+datastore
+ .find(Hotel.class)
+ .update(UpdateOperators.set("name", "Fairmont Chateau Laurier"))
+ .execute();
+```
+
+The `execute()` can optionally take [UpdateOptions](/javadoc/dev/morphia/UpdateOptions.html) if there are any options you might want to apply to your update statement.
+
+Embedded documents are updated the same way.
+To change the name of the city in the address, one would use something like this:
+
+```java
+datastore
+ .find(Hotel.class)
+ .update(UpdateOperators.set("address.city", "Ottawa"))
+ .execute();
+```
+
+Values can also be removed from documents as shown below:
+
+```java
+datastore
+ .find(Hotel.class)
+ .update(UpdateOperators.unset("name"))
+ .execute();
+```
+
+After this update, the name of the hotel would be `null` when the entity is loaded.
+
+### Multiple Updates
+
+By default, an update operation will only update the first document matching the query.
+This behavior can be modified via the optional
+[UpdateOptions](/javadoc/dev/morphia/UpdateOptions.html) parameter on `execute()`:
+
+```java
+datastore
+ .find(Hotel.class)
+ .inc("stars")
+ .execute(new UpdateOptions()
+ .multi(true));
+```
+
+### Upserts
+
+In some cases, updates are issued against a query that might not match any documents.
+In these cases, it's often fine for those updates to simply pass with no effect.
+In other cases, it's desirable to create an initial document matching the query parameters.
+Examples of this might include user high scores, e.g. In cases like this, we have the option to use an upsert:
+
+```java
+datastore
+ .find(Hotel.class)
+ .filter(gt("stars", 100))
+ .update()
+ .execute(new UpdateOptions()
+ .upsert(true));
+
+// creates { "_id" : ObjectId("4c60629d2f1200000000161d"), "stars" : 50 }
+```
+
+### Checking results
+
+In all this one thing we haven't really looked at is how to verify the results of an update.
+The `execute()` method returns an instance of
+`com.mongodb.client.result.UpdateResult`.
+Using this class, you can get specific numbers from the update operation as well as any generated ID as the result of an upsert.
+
+### Returning the updated entity
+
+There are times when a document needs to be updated and also fetched from the database.
+In the server documentation, this is referred to as [findAndModify](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/).
+In Morphia, this functionality is exposed through the
+[Query#modify()](/javadoc/dev/morphia/query/Query.html#modify(dev.morphia.query.updates.UpdateOperator,dev.morphia.query.updates.UpdateOperator...))
+method. With this method, you can choose to return the updated entity in either the
+state before or after the update. The default is to return the entity in the _before_ state.
+This can be changed by passing in a `ModifyOptions` reference to the operation:
+
+```java
+datastore
+ .find(Hotel.class)
+ .modify(UpdateOperators.set("address.city", "Ottawa"))
+ .execute(new ModifyOptions()
+ .returnDocument(ReturnDocument.AFTER));
+```
+
+### Merges
+
+A specialized form of an update is the [merge()](/javadoc/dev/morphia/Datastore.html#merge(T)) operation.
+A common case in scenarios where multiple subsystems or applications share a database is where one part of the system might only have part of a larger entity. e.g., a
+[DTO](https://en.wikipedia.org/wiki/Data_transfer_object) might only have a subset of an entity necessary to perform the duties of that particular service.
+Updating the database with the partial entities can be problematic because it forces the application developer to inspect an entity's state and manually generate the correct set of update statements.
+Morphia 2.0 introduced the `merge()` method to help cover this case.
+Using `merge()`, a specific set of `$set` updates are issued to only save fields as defined on the DTO type itself (which, of course, must be annotated with `@Entity` like any other Morphia type).
+
+This is useful but limited.
+What happens to any null fields and empty Lists?
+Using `MorphiaConfig`, Morphia can be configured to not persist those fields such that they never end up in the database.
+In the above scenario, however, Morphia is only issuing a `$set` for the fields that should be persisted which leaves potentially outdated information in the database. (e.g., say a process removes the final item from a List in memory. `merge()` would actually *leave* that last item in the database because an update would not be issued for that empty List.) In 2.2, a new value is added to the optional [InsertOneOptions](/javadoc/dev/morphia/InsertOneOptions.html) to account for this.
+
+Setting [unsetMissing](/javadoc/dev/morphia/InsertOneOptions.html#unsetMissing(boolean)) to true, any property defined on an entity
+that isn't getting updated via `$set` will have a `$unset` operator defined.
+This will result in null properties and empty Lists getting removed from documents in the database so that they will reflect the current state in memory.
+
+Regardless of whether this value is set, `merge()` will issue a `find()` for that entity and will return the updated form from the database.
+Without using `unsetMissing()`, this is useful for merging the in memory state with what's in the database.
+With this value set, the two should be identical, of course.
+
+### Supported Operators
+Every effort is made to provide 100% coverage of all the operators offered by MongoDB. Below is listed all the currently supported
+operators. To see an example of an operator in action, click through to see the test cases for that operator.
+
+If an operator is missing and you think it should be included, please file an [issue](https://github.com/MorphiaOrg/morphia/issues) for that operator.
+
+#### Filters
+
+| Operator | Docs | Test Examples |
+|----------|------|---------------|
+| [$addToSet](http://docs.mongodb.org/manual/reference/operator/query/addToSet) | [UpdateOperators#addToSet(String,Object)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#addToSet(java.lang.String,java.lang.Object)) [UpdateOperators#addToSet(String,List)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#addToSet(java.lang.String,java.util.List)) | [TestAddToSet](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestAddToSet.java) |
+| [$bit](http://docs.mongodb.org/manual/reference/operator/query/bit) | [UpdateOperators#and(String,int)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#and(java.lang.String,int)) [UpdateOperators#bit(String,Number)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#bit(java.lang.String,java.lang.Number)) [UpdateOperators#or(String,int)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#or(java.lang.String,int)) [UpdateOperators#xor(String,int)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#xor(java.lang.String,int)) | [TestBit](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestBit.java) |
+| [$currentDate](http://docs.mongodb.org/manual/reference/operator/query/currentDate) | [UpdateOperators#currentDate(String)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#currentDate(java.lang.String)) | [TestCurrentDate](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestCurrentDate.java) |
+| [$dec](http://docs.mongodb.org/manual/reference/operator/query/dec) | [UpdateOperators#dec(String)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#dec(java.lang.String)) [UpdateOperators#dec(String,Number)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#dec(java.lang.String,java.lang.Number)) | [TestDec](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestDec.java) |
+| [$each](http://docs.mongodb.org/manual/reference/operator/query/each) | [UpdateOperators#push(String,List)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#push(java.lang.String,java.util.List)) | [TestEach](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestEach.java) |
+| [$inc](http://docs.mongodb.org/manual/reference/operator/query/inc) | [UpdateOperators#inc(String,Number)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#inc(java.lang.String,java.lang.Number)) [UpdateOperators#inc(String)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#inc(java.lang.String)) | [TestInc](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestInc.java) |
+| [$max](http://docs.mongodb.org/manual/reference/operator/query/max) | [UpdateOperators#max(String,Number)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#max(java.lang.String,java.lang.Number)) [UpdateOperators#max(String,Temporal)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#max(java.lang.String,java.time.temporal.Temporal)) [UpdateOperators#max(String,Date)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#max(java.lang.String,java.util.Date)) | [TestMax](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestMax.java) |
+| [$min](http://docs.mongodb.org/manual/reference/operator/query/min) | [UpdateOperators#min(String,Number)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#min(java.lang.String,java.lang.Number)) [UpdateOperators#min(String,Temporal)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#min(java.lang.String,java.time.temporal.Temporal)) [UpdateOperators#min(String,Date)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#min(java.lang.String,java.util.Date)) | [TestMin](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestMin.java) |
+| [$mul](http://docs.mongodb.org/manual/reference/operator/query/mul) | [UpdateOperators#mul(String,Number)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#mul(java.lang.String,java.lang.Number)) | [TestMul](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestMul.java) |
+| [$pop](http://docs.mongodb.org/manual/reference/operator/query/pop) | [UpdateOperators#pop(String)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#pop(java.lang.String)) | [TestPop](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestPop.java) |
+| [$pull](http://docs.mongodb.org/manual/reference/operator/query/pull) | [UpdateOperators#pull(String,Filter...)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#pull(java.lang.String,dev.morphia.query.filters.Filter...)) [UpdateOperators#pull(String,Object)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#pull(java.lang.String,java.lang.Object)) | [TestPull](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestPull.java) |
+| [$pullAll](http://docs.mongodb.org/manual/reference/operator/query/pullAll) | [UpdateOperators#pullAll(String,List)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#pullAll(java.lang.String,java.util.List)) | [TestPullAll](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestPullAll.java) |
+| [$push](http://docs.mongodb.org/manual/reference/operator/query/push) | [UpdateOperators#push(String,Object)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#push(java.lang.String,java.lang.Object)) | [TestPush](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestPush.java) |
+| [$rename](http://docs.mongodb.org/manual/reference/operator/query/rename) | [UpdateOperators#rename(String,String)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#rename(java.lang.String,java.lang.String)) | [TestRename](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestRename.java) |
+| [$set](http://docs.mongodb.org/manual/reference/operator/query/set) | [UpdateOperators#set(String,Object)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#set(java.lang.String,java.lang.Object)) [UpdateOperators#set(Object)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#set(java.lang.Object)) | [TestSet](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestSet.java) |
+| [$setOnInsert](http://docs.mongodb.org/manual/reference/operator/query/setOnInsert) | [UpdateOperators#setOnInsert(Map)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#setOnInsert(java.util.Map)) | [TestSetOnInsert](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestSetOnInsert.java) |
+| [$unset](http://docs.mongodb.org/manual/reference/operator/query/unset) | [UpdateOperators#unset(String,String...)](/javadoc/dev/morphia/query/updates/UpdateOperators.html#unset(java.lang.String,java.lang.String...)) | [TestUnset](https://github.com/MorphiaOrg/morphia/blob/master/core/src/test/java/dev/morphia/test/query/updates/TestUnset.java) |
diff --git a/docs/content/support/_index.md b/docs/content/support/_index.md
new file mode 100644
index 00000000000..e3d87cca2a6
--- /dev/null
+++ b/docs/content/support/_index.md
@@ -0,0 +1,37 @@
+---
+title: "Support"
+description: "Get help, report issues, and contribute to Morphia"
+---
+
+# Issues & Help
+
+We are lucky to have a vibrant MongoDB Java community with lots of varying experience of using Morphia. We often find the quickest way to get support for general questions is through [GitHub discussions](https://github.com/MorphiaOrg/morphia/discussions), [the MongoDB community forums](https://community.mongodb.com/c/drivers-odms-connectors/), or through [Stack Overflow](https://stackoverflow.com/questions/tagged/morphia).
+
+There is also a small but growing community on Discord which can be found [here](https://discord.gg/saZsJescBa).
+
+## Bugs / Feature Requests
+
+If you think you've found a bug or want to see a new feature in Morphia, please open an issue on [GitHub](https://github.com/MorphiaOrg/morphia/issues). Please provide as much information as possible (including version numbers) about the issue type and how to reproduce it. Ideally, if you can create a reproducer for the issue at hand, that would be even more helpful. To help with this, please take a look at the [reproducer](https://github.com/MorphiaOrg/reproducer) project. This will help you set up a quick environment for reproducing your issue and providing a working example to examine. This project can either be shared via a GitHub repo on your account or perhaps attaching a zip of the project to the associated issue.
+
+{{% notice tip %}}
+Providing a [reproducer](https://github.com/MorphiaOrg/reproducer) is the fastest way to help resolve your issue. It cuts down the guesswork and labor required to recreate the problem locally so that root causes can be investigated. If the repository is shared via GitHub (or other public repository), it even allows the opportunity for tweaks and suggestions to be made by both you and the maintainers to more quickly isolate and provide a fix.
+{{% /notice %}}
+
+## Pull Requests
+
+We are happy to accept contributions to help improve Morphia. We will guide user contributions to ensure they meet the standards of the codebase. Please ensure that any pull requests include documentation, tests, and also pass the build checks.
+
+To get started, check out the source and work on a branch:
+
+```bash
+$ git clone https://github.com/MorphiaOrg/morphia.git
+$ cd morphia
+$ git checkout -b myNewFeature
+```
+
+Finally, ensure that the code passes all the checks:
+
+```bash
+$ cd core
+$ mvn -Dcode-audits
+```
diff --git a/docs/data/menu.yaml b/docs/data/menu.yaml
new file mode 100644
index 00000000000..cb0163d2f38
--- /dev/null
+++ b/docs/data/menu.yaml
@@ -0,0 +1,51 @@
+main:
+ - name: "Getting Started"
+ url: "/getting-started/"
+ weight: 1
+ items:
+ - name: "Quick Tour"
+ url: "/getting-started/quicktour/"
+ - name: "Migrating"
+ url: "/getting-started/migrating/"
+
+ - name: "Features"
+ url: "/features/"
+ weight: 2
+ items:
+ - name: "Configuration"
+ url: "/features/configuration/"
+ - name: "Kotlin"
+ url: "/features/kotlin/"
+ - name: "Mapping"
+ url: "/features/mapping/"
+ - name: "Indexing"
+ url: "/features/indexing/"
+ - name: "Sharding"
+ url: "/features/sharding/"
+ - name: "Querying"
+ url: "/features/queries/"
+ - name: "Updating"
+ url: "/features/updates/"
+ - name: "Deleting"
+ url: "/features/deletes/"
+ - name: "Aggregation"
+ url: "/features/aggregations/"
+ - name: "Text Search"
+ url: "/features/text-search/"
+ - name: "References"
+ url: "/features/references/"
+ - name: "Transactions"
+ url: "/features/transactions/"
+ - name: "Life Cycle Methods"
+ url: "/features/lifecycle-methods/"
+ - name: "Schema Validation"
+ url: "/features/schema-validation/"
+
+ - name: "Support"
+ url: "/support/"
+ weight: 3
+
+ - name: "Javadoc"
+ url: "/javadoc/"
+ weight: 4
+ external: true
diff --git a/docs/hugo.toml b/docs/hugo.toml
index 9bc064151c3..90cf095c590 100644
--- a/docs/hugo.toml
+++ b/docs/hugo.toml
@@ -1,7 +1,6 @@
baseURL = "https://morphia.dev/"
languageCode = "en-us"
title = "Morphia Documentation"
-theme = "morphia-docs"
# Version for this branch
[params]
diff --git a/docs/layouts/_default/baseof.html b/docs/layouts/_default/baseof.html
new file mode 100644
index 00000000000..af907bfab87
--- /dev/null
+++ b/docs/layouts/_default/baseof.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+ {{ if .Title }}{{ .Title }} | {{ end }}{{ .Site.Title }}
+
+
+
+
+ {{ partial "header.html" . }}
+