1. Overview
1.概述
In this tutorial, we’ll understand how to use Morphia, an Object Document Mapper (ODM) for MongoDB in Java.
在本教程中,我们将了解如何使用Morphia,这是Java中MongoDB的对象文档映射器(ODM)。
In the process, we’ll also understand what is an ODM and how it facilitates working with MongoDB.
在这个过程中,我们还将了解什么是ODM,以及它如何促进与MongoDB的合作。
2. What Is an ODM?
2.什么是ODM?
For those uninitiated in this area, MongoDB is a document-oriented database built to be distributed by nature. Document-oriented databases, in simple terms, manage documents, which are nothing but a schema-less way of organizing semi-structured data. They fall under a broader and loosely defined umbrella of NoSQL databases, named after their apparent departure from the traditional organization of SQL databases.
对于那些不了解这一领域的人来说,MongoDB是一个面向文档的数据库,其本质是分布式的。简单地说,面向文档的数据库管理文档,它只不过是一种组织半结构化数据的无模式方法。它们属于更广泛的、定义松散的NoSQL数据库的范畴,因其明显偏离了SQL数据库的传统组织方式而得名。
MongoDB provides drivers for almost all popular programming languages like Java. These drivers offer a layer of abstraction for working with MongoDB so that we aren’t working with Wire Protocol directly. Think of this as Oracle providing an implementation of the JDBC driver for their relational database.
MongoDB提供了几乎所有流行的编程语言(如Java)的驱动程序。这些驱动程序为与MongoDB的合作提供了一层抽象,这样我们就不会直接与Wire Protocol合作。可以认为这是Oracle为其关系型数据库提供的JDBC驱动程序的实现。
However, if we recall our days working with JDBC directly, we can appreciate how messy it can get — especially in an object-oriented paradigm. Fortunately, we have Object Relational Mapping (ORM) frameworks like Hibernate to our rescue. It isn’t very different for MongoDB.
然而,如果我们回忆一下我们直接使用JDBC的日子,我们就会明白它可以变得多么混乱–特别是在面向对象的范式中。幸运的是,我们有Hibernate这样的对象关系映射(ORM)框架来拯救我们。对于MongoDB来说,这并没有什么不同。
While we can certainly work with the low-level driver, it requires a lot more boilerplate to accomplish the task. Here, we’ve got a similar concept to ORM called Object Document Mapper (ODM). Morphia exactly fills that space for the Java programming language and works on top of the Java driver for MongoDB.
虽然我们当然可以使用低级别的驱动程序,但它需要更多的模板来完成任务。在这里,我们有一个类似于ORM的概念,叫做对象文档映射器(ODM)。Morphia正好填补了Java编程语言的这一空间,并在MongoDB的Java驱动之上工作。
3. Setting up Dependencies
3.设置依赖关系
We’ve seen enough theory to get us into some code. For our examples, we’ll model a library of books and see how we can manage it in MongoDB using Morphia.
我们已经看到了足够的理论,可以让我们进入一些代码。在我们的例子中,我们将建立一个图书库的模型,看看我们如何使用Morphia在MongoDB中管理它。
But before we begin, we’ll need to set-up some of the dependencies.
但在我们开始之前,我们需要设置一些依赖性。
3.1. MongoDB
3.1.梦之城_梦之城娱乐_梦之城国际娱乐_梦之城国际娱乐平台
We need to have a running instance of MongoDB to work with. There are several ways to get this, and the simplest is to download and install community edition on our local machine.
我们需要有一个正在运行的MongoDB实例来进行工作。有几种方法可以获得这些,最简单的是在我们的本地机器上下载并安装社区版。
We should leave all default configurations as-is, including the port on which MongoDB runs.
我们应该保持所有的默认配置不变,包括MongoDB的运行端口。
3.2. Morphia
3.2.莫菲亚
We can download the pre-built JARs for Morphia from Maven Central and use them in our Java project.
我们可以从Maven Central下载Morphia的预建JARs,并在我们的Java项目中使用它们。
However, the simplest way is to use a dependency management tool like Maven:
不过,最简单的方法是使用Maven这样的依赖管理工具。
<dependency>
<groupId>dev.morphia.morphia</groupId>
<artifactId>core</artifactId>
<version>1.5.3</version>
</dependency>
4. How to Connect Using Morphia?
4.如何使用Morphia连接?
Now that we have MongoDB installed and running and have set-up Morphia in our Java project, we’re ready to connect to MongoDB using Morphia.
现在,我们已经安装并运行了MongoDB,并在我们的Java项目中设置了Morphia,我们准备使用Morphia连接到MongoDB。
Let’s see how we can accomplish that:
让我们看看我们如何能够实现这一目标。
Morphia morphia = new Morphia();
morphia.mapPackage("com.baeldung.morphia");
Datastore datastore = morphia.createDatastore(new MongoClient(), "library");
datastore.ensureIndexes();
That’s pretty much it! Let’s understand this better. We need two things for our mapping operations to work:
基本上就是这样了!让我们更好地理解这一点。我们需要两样东西来使我们的映射操作发挥作用。
- A Mapper: This is responsible for mapping our Java POJOs to MongoDB Collections. In our code snippet above, Morphia is the class responsible for that. Note how we’re configuring the package where it should look for our POJOs.
- A Connection: This is the connection to a MongoDB database on which the mapper can execute different operations. The class Datastore takes as a parameter an instance of MongoClient (from the Java MongoDB driver) and the name of the MongoDB database, returning an active connection to work with.
So, we’re all set to use this Datastore and work with our entities.
所以,我们已经准备好使用这个Datastore并与我们的实体一起工作。
5. How to Work with Entities?
5.如何与实体企业合作?
Before we can use our freshly minted Datastore, we need to define some domain entities to work with.
在我们可以使用我们新造的Datastore之前,我们需要定义一些域实体来工作。
5.1. Simple Entity
5.1.简单的实体
Let’s begin by defining a simple Book entity with some attributes:
让我们首先定义一个简单的带有一些属性的Book实体。
@Entity("Books")
public class Book {
@Id
private String isbn;
private String title;
private String author;
@Property("price")
private double cost;
// constructors, getters, setters and hashCode, equals, toString implementations
}
There are a couple of interesting things to note here:
这里有几件有趣的事情需要注意。
- Notice the annotation @Entity that qualifies this POJO for ODM mapping by Morphia
- Morphia, by default, maps an entity to a collection in MongoDB by the name of its class, but we can explicitly override this (like we’ve done for the entity Book here)
- Morphia, by default, maps the variables in an entity to the keys in a MongoDB collection by the name of the variable, but again we can override this (like we’ve done for the variable cost here)
- Lastly, we need to mark a variable in the entity to act as the primary key by the annotation @Id (like we’re using ISBN for our book here)
5.2. Entities with Relationships
5.2.有关系的实体
In the real world, though, entities are hardly as simple as they look and have complex relationships with each other. For instance, our simple entity Book can have a Publisher and can reference other companion books. How do we model them?
然而,在现实世界中,实体很难像它们看起来那么简单,它们之间有复杂的关系。例如,我们的简单实体Book可以有一个Publisher,并且可以引用其他的配套书籍。我们如何为它们建模呢?
MongoDB offers two mechanisms to build relationships — Referencing and Embedding. As the name suggests, with referencing, MongoDB stores related data as a separate document in the same or a different collection and just references it using its id.
MongoDB提供两种机制来建立关系–引用和嵌入。顾名思义,通过引用,MongoDB将相关数据作为一个单独的文档存储在同一个或不同的集合中,并使用其id对其进行引用。
On the contrary, with embedding, MongoDB stores or rather embeds the relation within the parent document itself.
相反,通过嵌入,MongoDB在父文档本身中存储或者说嵌入了关系。
Let’s see how we can use them. Let’s begin by embedding Publisher in our Book:
让我们看看我们如何使用它们。让我们首先把Publisher嵌入我们的Book中。
@Embedded
private Publisher publisher;
Simple enough. Now let’s go ahead and add references to other books:
够简单了。现在让我们继续前进,增加对其他书籍的参考。
@Reference
private List<Book> companionBooks;
That’s it — Morphia provides convenient annotations to model relationships as supported by MongoDB. The choice of referencing vs embedding, however, should draw from data model complexity, redundancy, and consistency amongst other considerations.
就是这样–Morphia为MongoDB所支持的关系建模提供了方便的注释。然而,选择引用与嵌入,应该从数据模型的复杂性、冗余度和一致性等方面考虑。
The exercise is similar to normalization in relational databases.
这项工作类似于关系型数据库中的规范化。
Now, we’re ready to perform some operations on Book using Datastore.
现在,我们准备使用Datastore对Book执行一些操作。
6. Some Basic Operations
6.一些基本操作
Let’s see how to work with some of the basic operations using Morphia.
让我们来看看如何使用Morphia进行一些基本操作。
6.1. Save
6.1. 保存
Let’s begin with the simplest of the operations, creating an instance of Book in our MongoDB database library:
让我们从最简单的操作开始,在我们的MongoDB数据库Book中创建一个library的实例。
Publisher publisher = new Publisher(new ObjectId(), "Awsome Publisher");
Book book = new Book("9781565927186", "Learning Java", "Tom Kirkman", 3.95, publisher);
Book companionBook = new Book("9789332575103", "Java Performance Companion",
"Tom Kirkman", 1.95, publisher);
book.addCompanionBooks(companionBook);
datastore.save(companionBook);
datastore.save(book);
This is enough to let Morphia create a collection in our MongoDB database, if it does not exist, and perform an upsert operation.
这足以让Morphia在我们的MongoDB数据库中创建一个集合,如果它不存在的话,并执行一个upsert操作。
6.2. Query
6.2. 查询
Let’s see if we’re able to query the book we just created in MongoDB:
让我们看看我们是否能够在MongoDB中查询我们刚刚创建的书。
List<Book> books = datastore.createQuery(Book.class)
.field("title")
.contains("Learning Java")
.find()
.toList();
assertEquals(1, books.size());
assertEquals(book, books.get(0));
Querying a document in Morphia begins with creating a query using Datastore and then declaratively adding filters, to the delight of those in love with functional programming!
在Morphia中查询一个文档,首先要使用Datastore创建一个查询,然后声明性地添加过滤器,这让那些热爱函数式编程的人感到很高兴!
Morphia supports much more complex query construction with filters and operators. Moreover, Morphia allows for limiting, skipping, and ordering of results in the query.
Morphia支持更多的过滤器和运算符的复杂查询结构。此外,Morphia允许在查询中对结果进行限制、跳过和排序。
What’s more, Morphia allows us to use raw queries written with the Java driver for MongoDB for more control, should that be needed.
更重要的是,Morphia允许我们使用用MongoDB的Java驱动编写的原始查询,以便在需要时进行更多的控制。
6.3. Update
6.3.更新
Although a save operation can handle updates if the primary key matches, Morphia provides ways to selectively update documents:
尽管如果主键匹配,保存操作可以处理更新,但Morphia提供了选择性更新文档的方法。
Query<Book> query = datastore.createQuery(Book.class)
.field("title")
.contains("Learning Java");
UpdateOperations<Book> updates = datastore.createUpdateOperations(Book.class)
.inc("price", 1);
datastore.update(query, updates);
List<Book> books = datastore.createQuery(Book.class)
.field("title")
.contains("Learning Java")
.find()
.toList();
assertEquals(4.95, books.get(0).getCost());
Here, we’re building a query and an update operation to increase by one the price of all books returned by the query.
在这里,我们要建立一个查询和一个更新操作,将查询返回的所有书籍的价格增加一个。
6.4. Delete
6.4.删除
Finally, that which has been created must be deleted! Again, with Morphia, it’s quite intuitive:
最后,已经创建的东西必须被删除!同样,对于Morphia来说,这是很直观的。
Query<Book> query = datastore.createQuery(Book.class)
.field("title")
.contains("Learning Java");
datastore.delete(query);
List<Book> books = datastore.createQuery(Book.class)
.field("title")
.contains("Learning Java")
.find()
.toList();
assertEquals(0, books.size());
We create the query quite similarly as before and run the delete operation on the Datastore.
我们和以前一样创建查询,在Datastore上运行删除操作。
7. Advanced Usage
7.高级用法
MongoDB has some advanced operations like Aggregation, Indexing, and many others. While it isn’t possible to perform all of that using Morphia, it’s certainly possible to achieve some of that. For others, sadly, we’ll have to fall back to the Java driver for MongoDB.
MongoDB有一些高级操作,如聚合、索引和其他许多操作。虽然不可能用Morphia执行所有这些操作,但肯定可以实现其中的一些。遗憾的是,对于其他的操作,我们将不得不退回到MongoDB的Java驱动。
Let’s focus on some of these advanced operations that we can perform through Morphia.
让我们关注一下我们可以通过Morphia进行的一些高级操作。
7.1. Aggregation
7.1 聚合
Aggregation in MongoDB allows us to define a series of operations in a pipeline that can operate on a set of documents and produce aggregated output.
MongoDB中的聚合允许我们定义管道中的一系列操作,这些操作可以对一组文档进行操作并产生聚合的输出。
Morphia has an API to support such an aggregation pipeline.
Morphia有一个API来支持这样一个聚合管道。
Let’s assume we wish to aggregate our library data in such a manner that we have all the books grouped by their author:
假设我们希望以这样一种方式汇总我们的图书馆数据,即我们将所有的书籍按其作者分组。
Iterator<Author> iterator = datastore.createAggregation(Book.class)
.group("author", grouping("books", push("title")))
.out(Author.class);
So, how does this work? We begin by creating an aggregation pipeline using the same old Datastore. We have to provide the entity on which we wish to perform aggregation operations, for instance, Book here.
那么,这是如何工作的呢?我们首先使用相同的旧Datastore创建一个聚合管道。我们必须提供我们希望执行聚合操作的实体,例如,这里是Book。
Next, we want to group documents by “author” and aggregate their “title” under a key called “books”. Finally, we’re working with an ODM here. So, we have to define an entity to collect our aggregated data — in our case, it’s Author.
接下来,我们要按 “作者 “对文件进行分组,并将其 “标题 “汇总到一个叫做 “书籍 “的键下。最后,我们在这里使用一个ODM。因此,我们必须定义一个实体来收集我们的聚合数据–在我们的例子中,它是Author。
Of course, we have to define an entity called Author with a variable called books:
当然,我们必须定义一个名为Author的实体和一个名为books的变量。
@Entity
public class Author {
@Id
private String name;
private List<String> books;
// other necessary getters and setters
}
This, of course, just scratches the surface of a very powerful construct provided by MongoDB and can be explored further for details.
当然,这只是MongoDB所提供的一个非常强大的结构的表面,可以进一步探索细节。
7.2. Projection
7.2.投影
Projection in MongoDB allows us to select only the fields we want to fetch from documents in our queries. In case document structure is complex and heavy, this can be really useful when we need only a few fields.
MongoDB中的投影允许我们在查询中只选择我们想从文档中获取的字段。如果文档结构复杂而繁重,当我们只需要几个字段时,这可能真的很有用。
Let’s suppose we only need to fetch books with their title in our query:
让我们假设我们只需要在查询中获取带有书名的书籍。
List<Book> books = datastore.createQuery(Book.class)
.field("title")
.contains("Learning Java")
.project("title", true)
.find()
.toList();
assertEquals("Learning Java", books.get(0).getTitle());
assertNull(books.get(0).getAuthor());
Here, as we can see, we only get back the title in our result and not the author and other fields. We should, however, be careful in using the projected output in saving back to MongoDB. This may result in data loss!
在这里,我们可以看到,我们的结果中只得到了标题,而没有得到作者和其他字段。然而,我们在使用预测输出保存到MongoDB时应该小心。这可能会导致数据丢失。
7.3. Indexing
7.3.编制索引
Indexes play a very important role in query optimization with databases — relational as well as many non-relational ones.
索引在数据库的查询优化中起着非常重要的作用–关系型数据库以及许多非关系型数据库。
MongoDB defines indexes at the level of the collection with a unique index created on the primary key by default. Moreover, MongoDB allows indexes to be created on any field or sub-field within a document. We should choose to create an index on a key depending on the query we wish to create.
MongoDB 在集合层面上定义索引,默认在主键上创建唯一的索引。此外,MongoDB允许在文档中的任何字段或子字段上创建索引。我们应该根据我们想要创建的查询来选择在一个键上创建索引。
For instance, in our example, we may wish to create an index on the field “title” of Book as we often end up querying on it:
例如,在我们的例子中,我们可能希望在Book的 “title “字段上创建一个索引,因为我们经常要对它进行查询。
@Indexes({
@Index(
fields = @Field("title"),
options = @IndexOptions(name = "book_title")
)
})
public class Book {
// ...
@Property
private String title;
// ...
}
Of course, we can pass additional indexing options to tailor the nuances of the index that gets created. Note that the field should be annotated by @Property to be used in an index.
当然,我们可以传递额外的索引选项来定制被创建的索引的细微差别。请注意,字段应该由@Property来注释,以便在索引中使用。
Moreover, apart from the class-level index, Morphia has an annotation to define a field-level index as well.
此外,除了班级级别的索引外,Morphia还有一个注释来定义领域级别的索引。
7.4. Schema Validation
7.4 方案验证
We’ve got an option to provide data validation rules for a collection that MongoDB can use while performing an update or insert operation. Morphia supports this through their APIs.
我们有一个选项,可以为一个集合提供数据验证规则,MongoDB可以在执行更新或插入操作时使用该规则。Morphia通过其API支持这一点。
Let’s say that we don’t want to insert a book without a valid price. We can leverage schema validation to achieve this:
比方说,我们不想插入没有有效价格的书。我们可以利用模式验证来实现这一点。
@Validation("{ price : { $gt : 0 } }")
public class Book {
// ...
@Property("price")
private double cost;
// ...
}
There is a rich set of validations provided by MongoDB that can be employed here.
这里可以采用MongoDB提供的一套丰富的验证方法。
8. Alternative MongoDB ODMs
8.替代的MongoDB ODMs
Morphia is not the only available MongoDB ODM for Java. There are several others that we can consider to use in our applications. A discussion on comparison with Morphia is not possible here, but it is always useful to know our options:
Morphia并不是唯一可用的Java MongoDB ODM。我们可以考虑在我们的应用程序中使用其他几个。这里不可能讨论与Morphia的比较,但了解我们的选择总是有用的。
- Spring Data: Provides a Spring-based programming model for working with MongoDB
- MongoJack: Provides direct mapping from JSON to MongoDB objects
This is not a complete list of MongoDB ODMs for Java, but there are some interesting alternates available!
这不是一个完整的Java的MongoDB ODM列表,但有一些有趣的替代方案可用
9. Conclusion
9.结语
In this article, we understood the basic details of MongoDB and the use of an ODM to connect and operate on MongoDB from a programing language like Java. We further explored Morphia as a MongoDB ODM for Java and the various capabilities it has.
在这篇文章中,我们了解了MongoDB的基本细节以及使用ODM从Java这样的编程语言连接和操作MongoDB。我们进一步探讨了Morphia作为Java的MongoDB ODM以及它的各种功能。
As always, the code can be found over on GitHub.
一如既往,代码可以在GitHub上找到,。