4. MongoDB支持
MongoDB支持包含以下总结的各种功能。
-
Spring配置支持使用基于Java的@Configuration类或Mongo驱动程序实例和副本集的XML名称空间
-
MongoTemplate帮助类,提高生产力执行常见的Mongo操作。包括文档和POJO之间的集成对象映射。
-
异常转换成Spring的可移植数据访问异常层次结构
-
功能丰富的对象映射与Spring的转换服务集成
-
基于注释的映射元数据,但可扩展以支持其他元数据格式
-
持久性和映射生命周期事件
-
基于Java的查询,标准和更新DSL
-
自动实现版本库接口,包括支持自定义查找器方法。
-
QueryDSL集成来支持类型安全查询。
-
跨存储持久性 - 对JPA实体的支持,使用MongoDB透明地持久/检索字段
-
Log4j日志appender
-
地理空间整合
对于大多数任务,您会发现自己正在使用 MongoTemplate
或存储库支持,这些支持都利用丰富的映射功能。MongoTemplate是寻找访问功能的地方,如递增计数器或临时CRUD操作。MongoTemplate还提供了回调方法,以便您轻松掌握低级别的API构件,例如 org.mongo.DB
直接与MongoDB进行通信。各种API构件的命名约定的目标是复制基础MongoDB Java驱动程序中的这些元素,以便将现有的知识轻松映射到Spring API上。
Spring MongoDB支持需要MongoDB 1.4或更高版本以及Java SE 5或更高版本。推荐使用最新的产品版本(本文中为2.4.9)。建立工作环境的简单方法是在STS中创建一个基于Spring的项目。
首先你需要建立一个正在运行的Mongodb服务器。有关如何启动MongoDB实例的说明,请参阅 Mongodb快速入门指南。一旦安装起来,MongoDB通常是执行以下命令的问题: MONGO_HOME/bin/mongod
要在STS中创建一个Spring项目,请转至File - > New - > Spring Template Project - > Simple Spring Utility Project - >在提示时按Yes。然后输入一个项目和一个包名,比如org.spring.mongodb.example。
然后将以下内容添加到pom.xml依赖项部分。
<依赖性> <! - 其他依赖项元素被省略 - > <dependency> <groupId> org.springframework.data </ groupId> <artifactId> spring-data-mongodb </ artifactId> <version> 1.4.1.RELEASE </ version> </ dependency> </依赖>
还要将pom.xml中的Spring版本更改为
<spring.framework.version> 3.2.8.RELEASE </spring.framework.version>
您还需要将Maven的Spring Milestone存储库的位置添加到与您的<dependencies />元素相同级别的pom.xml中
<库> <库> <ID>弹簧里程碑</ ID> <名称>弹簧的Maven MILESTONE库</名称> <URL> http://repo.spring.io/libs-milestone </ URL> </存储库> </ repositories>
存储库也可以在这里浏览。
您可能还需要设置日志记录级别DEBUG
以查看一些附加信息,编辑要具有的log4j.properties文件
log4j.category.org.springframework.data.document.mongodb = DEBUG log4j.appender.stdout.layout.ConversionPattern =%d {ABSOLUTE}%5p%40.40c:%4L - %m%n
创建一个简单的Person类来坚持
package org.spring.mongodb.example; public class Person { 私人字符串ID; 私人字符串名称; 私人 INT年龄; public Person(String name,int age){ this .name = name; 这个 .age =年龄; } public String getId(){ return id; } public String getName(){ return name; } public int getAge(){ return age; } @Override public String toString(){ return “Person [id =” + id + “,name =” + name + “,age =” + age + “]” ; } }
并运行一个主要的应用程序
package org.spring.mongodb.example; import static org.springframework.data.mongodb.core.query.Criteria.where; 导入 org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Query; import com.mongodb.Mongo; 公共 类 MongoApp { 私人 静态 最终登录日志= LogFactory.getLog(MongoApp。类); 公共 静态 无效的主要(字符串[]参数)抛出异常{ MongoOperations mongoOps = 新的 MongoTemplate(新的 Mongo(),“数据库”); mongoOps.insert(新人(“Joe”,34)); log.info(mongoOps.findOne(新的查询(其中(“名”)。是(“乔”)),人。类)); mongoOps.dropCollection(“person”); } }
这将产生以下输出
10:01:32,062 DEBUG apping.MongoPersistentEntityIndexCreator:80 - 分析类类org.spring.example.Person获取索引信息。 10:01:32,265调试ramework.data.mongodb.core.MongoTemplate:631 - 插入包含字段的DBObject:集合中的[_class,age,name]:Person 10:01:32,765在db.collection:database.Person中调用ramework.data.mongodb.core.MongoTemplate:1243 - findOne使用查询:{“name”:“Joe”} 10:01:32,953 INFO org.spring.mongodb.example.MongoApp:25 - Person [id = 4ddbba3c0be56b7e1b210166,name = Joe,age = 34] 10:01:32,984 DEBUG ramework.data.mongodb.core.MongoTemplate:375 - Dropped collection [database.person]
即使在这个简单的例子中,也没有什么需要注意的
-
您可以
MongoTemplate
使用标准com.mongodb.Mongo
对象和要使用的数据库的名称实例化Spring Mongo的中央助手类 。 -
这个映射器可以处理标准的POJO对象,而不需要额外的元数据(尽管你可以选择提供这些信息,参见这里)。
-
约定用于处理id字段,将其转换为存储在数据库中的ObjectId。
-
映射约定可以使用字段访问。注意Person类只有getter。
-
如果构造函数的参数名称与存储文档的字段名称相匹配,则将用于实例化对象
有一个github存储库,有几个例子,你可以下载和玩弄,以了解图书馆是如何工作的。
使用MongoDB和Spring的首要任务之一是com.mongodb.Mongo
使用IoC容器创建一个 对象。有两种主要的方法可以使用基于Java的bean元数据或基于XML的bean元数据。这些在下面的章节中讨论。
使用基于的Java bean的元数据登记的一个实例的一个例子com.mongodb.Mongo
如下所示
例4.1。使用基于Java的bean元数据注册一个com.mongodb.Mongo对象
@Configuration public class AppConfig { / * *使用标准的Mongo驱动程序API创建一个com.mongodb.Mongo实例。 * / public @Bean Mongo mongo()抛出 UnknownHostException { 返回 新的 Mongo(“localhost”); } }
这种方法允许你使用com.mongodb.Mongo
你可能已经习惯使用的标准 API,但是也会使用UnknownHostException checked异常来污染代码。检查异常的使用是不可取的,因为基于Java的bean元数据使用方法来设置对象依赖性,使得调用代码混乱。
另一种方法是com.mongodb.Mongo
使用Spring的容器注册一个实例 实例 MongoFactoryBean
。与com.mongodb.Mongo
直接实例化一个实例相比,FactoryBean方法不会抛出一个检查异常,并且还具有为容器提供一个ExceptionTranslator实现的附加优势,该实现将MongoDB异常转换为Spring便携式DataAccessException
层次结构中的异常, 以便使用@Repository
注释来批注数据访问类。Spring的DAO支持功能@Repository
描述了 这个层次结构和用法。
下面显示了一个支持@Repository
注释类异常转换的基于Java的bean元数据示例:
例4.2。使用Spring的MongoFactoryBean注册一个com.mongodb.Mongo对象并启用Spring的异常转换支持
@Configuration public class AppConfig { / * *创建com.mongodb.Mongo实例的工厂bean * / public @Bean MongoFactoryBean mongo(){ MongoFactoryBean mongo = new MongoFactoryBean(); mongo.setHost(“localhost”); 返回 mongo; } }
要访问com.mongodb.Mongo
由MongoFactoryBean
其他 @Configuration
或您自己的类创建的对象,请使用“ private @Autowired Mongo mongo;
”字段。
虽然可以使用Spring的传统 <beans/>
XML名称空间向com.mongodb.Mongo
容器注册一个实例,但XML可能相当冗长,因为它是通用的。XML名称空间是配置常用对象(如Mongo实例)的更好选择。mongo名称空间允许您创建Mongo实例服务器位置,副本集和选项。
要使用Mongo名称空间元素,您需要引用Mongo模式:
例4.3。XML模式来配置MongoDB
<?xml version =“1.0”encoding =“UTF-8”?> <beans xmlns = “http://www.springframework.org/schema/beans” xmlns:xsi = “http://www.w3.org / 2001 / XMLSchema-instance“ xmlns:context = ”http://www.springframework.org/schema/context“ xmlns:mongo = ”http://www.springframework.org/schema/data/mongo“ xsi:schemaLocation = “http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd“> <! - 默认的bean名称是'mongo' - > <mongo:mongo host =“localhost”port =“27017”/> </豆>
MongoOptions更高级的配置如下所示(注意这些不是推荐值)
例4.4。用于使用MongoOptions配置com.mongodb.Mongo对象的XML模式
<豆> <蒙戈:蒙戈 主机 = “localhost”的 端口 = “27017” > <蒙戈:选择 连接-每个主机 = “8” 螺纹允许的到块对连接乘法器 = “4” 连接超时 = “ 1000“ max-wait-time = ”1500}“ auto-connect-retry = ”true“ socket-keep-alive = ”true“ socket-timeout = ”1500“ slave-ok = ”true“ write-number = ”1 “ write-timeout = “0” write-fsync = “true”/> </ mongo:mongo /> </豆>
下面显示了使用副本集的配置。
例4.5。XML模式来配置具有副本集的com.mongodb.Mongo对象
<mongo:mongo id = “replicaSetMongo” replica-set = “127.0.0.1:27017,localhost:27018” />
虽然com.mongodb.Mongo
是MongoDB驱动程序API的入口点,但连接到特定的MongoDB数据库实例需要其他信息,如数据库名称和可选的用户名和密码。有了这些信息,您可以获得一个com.mongodb.DB对象并访问特定MongoDB数据库实例的所有功能。Spring提供org.springframework.data.mongodb.core.MongoDbFactory
如下所示的 界面来引导到数据库的连接。
公共 接口 MongoDbFactory { DB getDb()抛出 DataAccessException; DB getDb(String dbName)抛出 DataAccessException; }
以下部分显示如何使用容器与Java或基于XML的元数据配置MongoDbFactory
接口的实例 。反过来,您可以使用该MongoDbFactory
实例来配置MongoTemplate。
该类 org.springframework.data.mongodb.core.SimpleMongoDbFactory
提供了实现MongoDbFactory接口,并使用标准com.mongodb.Mongo
实例,数据库名称和可选的 org.springframework.data.authentication.UserCredentials
构造函数参数创建。
而不是使用IoC容器来创建一个MongoTemplate的实例,你可以在标准的Java代码中使用它们,如下所示。
公共 类 MongoApp { 私人 静态 最终登录日志= LogFactory.getLog(MongoApp。类); 公共 静态 无效的主要(字符串[]参数)抛出异常{ MongoOperations mongoOps = 新的 MongoTemplate(新的SimpleMongoDbFactory(新的Mongo(),“数据库”)); mongoOps.insert(新人(“Joe”,34)); log.info(mongoOps.findOne(新的查询(其中(“名”)。是(“乔”)),人。类)); mongoOps.dropCollection(“person”); } }
以粗体显示的代码突出显示了SimpleMongoDbFactory的使用,并且是入门部分中显示的列表之间的唯一区别。
为了在容器中注册一个MongoDbFactory实例,你可以编写代码,就像前面代码清单中突出显示的那样。一个简单的例子如下所示
@Configuration public class MongoConfiguration { 公共 @Bean MongoDbFactory mongoDbFactory()抛出异常{ 返回 新的 SimpleMongoDbFactory(新的 Mongo(),“数据库”); } }
要定义用户名和密码,请创建一个实例 org.springframework.data.authentication.UserCredentials
并将其传递给构造函数,如下所示。此列表还显示了使用MongoDbFactory
容器注册MongoTemplate的一个实例。
@Configuration public class MongoConfiguration { 公共 @Bean MongoDbFactory mongoDbFactory()抛出异常{ UserCredentials userCredentials = new UserCredentials(“joe”,“secret”); 返回 新的 SimpleMongoDbFactory(新的 Mongo(),“数据库”,userCredentials); } public @Bean MongoTemplate mongoTemplate()抛出异常{ 返回 新的 MongoTemplate(mongoDbFactory()); } }
SimpleMongoDbFactory
与使用<beans/>
命名空间相比,mongo命名空间提供了创建一个简便的方法 。简单的用法如下所示
<mongo:db-factory dbname = “database” >
在上面的例子中,com.mongodb.Mongo
使用默认的主机和端口号创建一个实例。在 SimpleMongoDbFactory
与容器注册由id标识“mongoDbFactory”,除非指定了id属性的值。
com.mongodb.Mongo
除了数据库的用户名和密码之外,您还可以为底层实例提供主机和端口, 如下所示。
<mongo:db-factory id = “anotherMongoDbFactory” host = “localhost” port = “27017” dbname = “database” username = “joe” password = “secret” />
如果您需要在com.mongodb.Mongo
用于创建实例的实例上配置其他选项 ,则SimpleMongoDbFactory
可以使用mongo-ref
如下所示的属性引用现有的bean 。为了显示另一个常见的使用模式,这个清单显示了使用一个属性占位符来参数化配置和创建 MongoTemplate
。
<context:property-placeholder location = “classpath:/com/myapp/mongodb/config/mongo.properties” /> <mongo:mongo host = “$ {mongo.host}” port = “$ {mongo.port}” > <mongo:options connections-per-host = “$ {mongo.connectionsPerHost}” threads-allowed-to-block auto-connect-retry = “$ { mongo.maxWaitTime}”为 连接乘法器 = “$ {mongo.threadsAllowedToBlockForConnectionMultiplier}” 连接超时 = “$ {mongo.connectTimeout}” 最大等待时间 = “$ {mongo.maxWaitTime} mongo.autoConnectRetry}“ socket-keep-alive = ”$ {mongo.socketKeepAlive}“ socket-timeout = ”$ {mongo。socketTimeout}“ slave-ok = “$ {mongo.slaveOk}” write-number = “1” write-timeout = “0” write-fsync = “true” /> </ mongo:mongo> <mongo:db-factory dbname = “database” mongo-ref = “mongo” /> <bean id = “anotherMongoTemplate” class = “org.springframework.data.mongodb.core.MongoTemplate” > <constructor-arg name = “mongoDbFactory” ref = “mongoDbFactory” /> </ bean>
激活审计功能只是将Spring Data Mongo auditing
名称空间元素添加到您的配置中:
例4.6。使用XML配置激活审计
<mongo:auditing mapping-context-ref = “customMappingContext”auditor -aware-ref = “yourAuditorAwareImpl” />
由于Spring数据MongoDB 1.4审计可以通过使用注释注释配置类来启用@EnableMongoAuditing
。
例4.7。使用JavaConfig激活审计
@Configuration @EnableMongoAuditing class Config { @Bean public AuditorAware <AuditableUser> myAuditorProvider(){ return new AuditorAwareImpl(); } }
如果你暴露类型的豆 AuditorAware
到 ApplicationContext
,审计基础设施会自动把它捡起来,并用它来确定当前用户要在域类型设置。如果您有多个注册的实现 ApplicationContext
,您可以通过显式设置auditorAwareRef
属性来选择要使用的实现@EnableJpaAuditing
。
该类MongoTemplate
位于包中org.springframework.data.document.mongodb
,是Spring MongoDB支持的中心类,它提供了一个与数据库交互的丰富功能集。该模板提供了创建,更新,删除和查询MongoDB文档的便利操作,并提供了域对象和MongoDB文档之间的映射。
![]() | 注意 |
---|---|
一旦配置, |
MongoDB文档和域类之间的映射是通过委托给接口的实现来完成的 MongoConverter
。Spring提供了两种实现方式,SimpleMappingConverter
以及MongoMappingConverter
,但你也可以编写自己的转换器。有关更多详细信息,请参阅MongoCoverters部分。
本MongoTemplate
类实现了接口MongoOperations
。在尽可能的方法上,这些方法MongoOperations
以MongoDB驱动程序Collection
对象上可用的方法命名,以使API熟悉现有的用于驱动程序API的MongoDB开发人员。例如,您将找到诸如“find”,“findAndModify”,“findOne”,“insert”,“remove”,“save”,“update”和“updateMulti”等方法。设计目标是尽可能地简化使用基础MongoDB驱动程序和MongoOperations
。在两个API之间的主要区别在于,MongOperations可以通过域对象,而不是DBObject
和有用于流利的API Query
, Criteria
,Update
DBObject
![]() | 注意 |
---|---|
引用 |
MongoTemplate
MongoMappingConverter 使用的默认转换器实现 。虽然 MongoMappingConverter
可以使用额外的元数据来指定对象到文档的映射,但它也能够通过使用用于映射ID和集合名称的一些约定来转换不包含额外元数据的对象。映射章节解释了这些约定以及映射注释的使用。
![]() | 注意 |
---|---|
在M2版本中 |
MongoTemplate的另一个核心功能是将MongoDB Java驱动程序中抛出的异常异常转换为Spring的可移植数据访问异常层次结构。有关更多信息,请参阅异常翻译部分。
MongoTemplate
如果您需要直接访问MongoDB驱动程序API以访问MongoTemplate没有明确公开的功能,则可以使用多种Execute回调方法之一来访问底层驱动程序API,但有许多便利方法 可帮助您轻松执行常见任务。执行回调会给你一个com.mongodb.Collection
或一个 com.mongodb.DB
对象的引用 。请参阅执行回调部分 了解更多信息。
现在我们来看一个如何MongoTemplate
在Spring容器的上下文中使用的例子 。
您可以使用Java创建并注册一个MongoTemplate实例,如下所示。
例4.8。注册一个com.mongodb.Mongo对象并启用Spring的异常转换支持
@Configuration public class AppConfig { 公共 @Bean蒙古语 mongo()抛出异常{ 返回 新的 Mongo(“本地主机”); } public @Bean MongoTemplate mongoTemplate()抛出异常{ 返回 新的 MongoTemplate(mongo(),“mydatabase”); } }
有几个重载MongoTemplate的构造函数。这些是
-
MongoTemplate
(Mongo mongo, String databaseName)
- 将com.mongodb.Mongo
对象和缺省数据库名称作为 对象。 -
MongoTemplate
(Mongo mongo, String databaseName, UserCredentials userCredentials)
- 添加用户名和密码进行数据库验证。 -
MongoTemplate
(MongoDbFactory mongoDbFactory)
- 使用一个封装了com.mongodb.Mongo
对象,数据库名称和用户名和密码的MongoDbFactory对象。 -
MongoTemplate
(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter)
- 添加一个MongoConverter用于映射。
你也可以使用Spring的XML <beans /> schema来配置一个MongoTemplate。
<mongo:mongo host = “localhost” port = “27017” /> <bean id = “mongoTemplate” class = “org.springframework.data.mongodb.core.MongoTemplate” > <constructor-arg ref = “mongo” /> <constructor-arg name = “databaseName” value = “geospatial” /> </豆>
其他的,你可能会喜欢创建时设置可选属性MongoTemplate
是默认 WriteResultCheckingPolicy
, WriteConcern
和 ReadPreference
。
![]() | 注意 |
---|---|
引用 |
在开发过程中,如果com.mongodb.WriteResult
从任何MongoDB操作返回的都包含错误,则记录或抛出异常非常方便。忘记在开发过程中这样做是很常见的,然后最终得到一个看起来像是成功运行的应用程序,但实际上数据库并没有根据您的期望进行修改。将MongoTemplate的WriteResultChecking属性设置为具有以下值的枚举:LOG,EXCEPTION或NONE,以记录错误,抛出和异常,或者什么也不做。缺省值是使用WriteResultChecking
NONE值。
如果尚未通过更高级别的驱动程序指定com.mongodb.WriteConcern
,则可以设置MongoTemplate
将用于写入操作的属性com.mongodb.Mongo
。如果WriteConcern
没有设置MongoTemplate的属性,它将默认为在MongoDB驱动程序的数据库或集合设置中设置的属性。
对于更高级的情况,您希望WriteConcern
在每个操作的基础上设置不同的 值(用于删除,更新,插入和保存操作),WriteConcernResolver
可以配置一个名为的策略接口MongoTemplate
。由于 MongoTemplate
用于保持POJO,因此 WriteConcernResolver
可以创建一个可以将特定POJO类映射到 WriteConcern
值的策略。的 WriteConcernResolver
接口如下所示。
公共 接口 WriteConcernResolver { WriteConcern解决(MongoAction行动); }
传入的参数MongoAction用于确定WriteConcern
要使用的值,或者将模板本身的值用作默认值。 MongoAction
包含正在写入的集合名称,java.lang.Class
POJO的转换DBObject
,以及作为枚举(MongoActionOperation
:REMOVE,UPDATE,INSERT,INSERT_LIST,SAVE)和其他一些上下文信息的操作。例如,
私有类MyAppWriteConcernResolver实现WriteConcernResolver { 公共WriteConcern解决(MongoAction行动){ if(action.getEntityClass()。getSimpleName()。contains(“Audit”)){ 返回WriteConcern.NONE; } else if(action.getEntityClass()。getSimpleName()。contains(“Metadata”)){ 返回WriteConcern.JOURNAL_SAFE; } return action.getDefaultWriteConcern(); } }
MongoTemplate
为您提供了一种简单的方法来保存,更新和删除您的域对象,并将这些对象映射到存储在MongoDB中的文档。
给定一个简单的类如Person
public class Person { 私人字符串ID; 私人字符串名称; 私人 INT年龄; public Person(String name,int age){ this .name = name; 这个 .age =年龄; } public String getId(){ return id; } public String getName(){ return name; } public int getAge(){ return age; } @Override public String toString(){ return “Person [id =” + id + “,name =” + name + “,age =” + age + “]” ; } }
您可以保存,更新和删除对象,如下所示。
![]() | 注意 |
---|---|
|
包 org.spring.example; import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Update.update; import static org.springframework.data.mongodb.core.query.Query.query; import java.util.List; 导入 org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import com.mongodb.Mongo; 公共 类 MongoApp { 私人 静态 最终登录日志= LogFactory.getLog(MongoApp。类); 公共 静态 无效的主要(字符串[]参数)抛出异常{ MongoOperations mongoOps = 新的 MongoTemplate(新的 SimpleMongoDbFactory(新的 Mongo(),“数据库”)); 人p = 新人(“乔”,34); // Insert用于将对象初始存储到数据库中。 mongoOps.insert(P); log.info(“Insert:” + p); //查找 P = mongoOps.findById(p.getId(),人。类); log.info(“找到:” + p); //更新 mongoOps.updateFirst(查询(其中(“名”)。是(“乔”)),更新(“时代”,35),人。类); P = mongoOps.findOne(查询(其中(“姓名”)。是(“乔”)),人。类); log.info(“Updated:” + p); //删除 mongoOps.remove(P); //检查删除工作 表<人>人= mongoOps.findAll(人。类); log.info(“人数=:” + people.size()); mongoOps.dropCollection(人类); } }
这将产生以下日志输出(包括MongoTemplate
自身的调试消息)
调试apping.MongoPersistentEntityIndexCreator:80 - 分析类的类org.spring.example.Person索引信息。 DEBUG work.data.mongodb.core.MongoTemplate:632 - 在集合中插入包含字段的DBObject:[_class,age,name]:person INFO org.spring.example.MongoApp:30 - Insert:Person [id = 4ddc6e784ce5b1eba3ceaf5c,name = Joe,age = 34] 在db.collection:database.person中调用work.data.mongodb.core.MongoTemplate:1246 - findOne使用查询:{“_id”:{“$ oid”:“4ddc6e784ce5b1eba3ceaf5c”}} INFO org.spring.example.MongoApp:34 - Found:Person [id = 4ddc6e784ce5b1eba3ceaf5c,name = Joe,age = 34] 调用work.data.mongodb.core.MongoTemplate:778 - 使用查询调用update:{“name”:“Joe”}并更新:{“$ set”:{“age”:35}}在collection中:person 在db.collection:database.person中调用work.data.mongodb.core.MongoTemplate:1246 - findOne使用查询:{“name”:“Joe”} INFO org.spring.example.MongoApp:39 - Updated:Person [id = 4ddc6e784ce5b1eba3ceaf5c,name = Joe,age = 35] DEBUG work.data.mongodb.core.MongoTemplate:823 - 删除使用查询:{“id”:“4ddc6e784ce5b1eba3ceaf5c”}在集合中:person INFO org.spring.example.MongoApp:46 - 人数=:0 DEBUG work.data.mongodb.core.MongoTemplate:376 - 删除集合[database.person]
使用存储在数据库中的MongoConverter
a String
和ObjectId
as 之间 存在隐式转换 ,并识别属性“Id”名称的约定。
![]() | 注意 |
---|---|
这个例子是为了显示在MongoTemplate上使用save,update和remove操作,而不是显示复杂的映射功能 |
本示例中使用的查询语法在“ 查询文档 ”一节中有更详细的说明。
MongoDB要求所有文档都有一个“_id”字段。如果您不提供一个驱动程序将分配 ObjectId
一个生成的值。在使用时, MongoMappingConverter
有一些规则来控制Java类的属性如何映射到这个'_id'字段。
下面概述什么属性将被映射到'_id'文档字段:
-
用
@Id
(org.springframework.data.annotation.Id
)注解的属性或字段 将被映射到“_id”字段。 -
没有注解但名为的属性或字段
id
将被映射到“_id”字段。
下面概述了在使用MappingMongoConverter
默认值的时候, 映射到_id文档字段的属性将进行什么类型的转换(如果有的话) MongoTemplate
。
-
在Java类中声明为String的id属性或字段将被转换并存储为
ObjectId
使用Spring的可能Converter<String, ObjectId>
。有效的转换规则被委托给MongoDB Java驱动程序。如果无法将其转换为ObjectId,则该值将作为字符串存储在数据库中。 -
BigInteger
在Java类中声明的id属性或字段 将被转换并存储为ObjectId
使用SpringConverter<BigInteger, ObjectId>
。
如果在Java类中没有上面指定的字段或属性,那么驱动程序将生成一个隐含的“_id”文件,但不会映射到Java类的属性或字段。
当查询和更新MongoTemplate
将使用转换器来处理转换的 Query
,并Update
对应于上述规则保存文档,以便在查询的字段名称和类型将能够匹配什么是在你的领域类的对象。
由于MongoDB集合可以包含代表各种类型实例的文档。一个很好的例子就是如果你存储了一个类的层次结构或者只是一个具有类型属性的类 Object
。在后一种情况下,在检索对象时,必须正确读入该属性中的值。因此,我们需要一种机制来存储类型信息和实际文档。
为了实现这一点,MappingMongoConverter
使用MongoTypeMapper
抽象与 DefaultMongoTypeMapper
主要实现。它的缺省行为是将完全限定的类名存储在_class
顶层文档的文档中,如果是复杂类型和声明的属性类型的子类型,则存储每个值。
例4.9。类型映射
公共 类 Sample { 联系价值; } public abstract class Contact {...} public class Person extends Contact {...} Sample sample = new Sample(); sample.value = new Person(); mongoTemplate.save(样品); { “_class”:“com.acme.Sample”, “value”:{ “_class”:“com.acme.Person” } }
正如你所看到的,我们存储了实际的根类持久化的类型信息,以及嵌套类型,因为它是复杂的,也是一个子类型Contact
。所以,如果你现在使用mongoTemplate.findAll(Object.class, "sample")
我们能够发现,存储的文件应该是一个 Sample
实例。我们也可以发现价值财产应该是一个Person
实际的。
如果你想避免把整个Java类名称写成类型信息,而是想使用某个键值,你可以@TypeAlias
在持久化的实体类中使用 注解。如果你需要自定义映射,更要看看 TypeInformationMapper
界面。该接口的一个实例可以在被配置 DefaultMongoTypeMapper
这反过来上配置MappingMongoConverter
。
下面的例子演示了如何配置自定义 MongoTypeMapper
在 MappingMongoConverter
。
例4.11。通过Spring Java Config配置一个自定义的MongoTypeMapper
类 CustomMongoTypeMapper 扩展 DefaultMongoTypeMapper { //在这里实现自定义类型映射 }
@Configuration 类 SampleMongoConfiguration扩展了 AbstractMongoConfiguration { @Override protected String getDatabaseName(){ return “database” ; } @Override public Mongo mongo()抛出 Exception { return new Mongo(); } @Bean @覆盖 公共 MappingMongoConverter mappingMongoConverter()抛出异常{ MappingMongoConverter mmc = super .mappingMongoConverter(); mmc.setTypeMapper(customTypeMapper()); 返回 mmc; } @Bean public MongoTypeMapper customTypeMapper(){ return new CustomMongoTypeMapper(); } }
请注意,我们正在扩展 AbstractMongoConfiguration
该类并覆盖MappingMongoConverter
我们配置自定义的位置的bean定义 MongoTypeMapper
。
例4.12。通过XML配置一个自定义的MongoTypeMapper
<mongo:mapping-converter type-mapper-ref = “customMongoTypeMapper” /> <bean name = “customMongoTypeMapper” class = “com.bubu.mongo.CustomMongoTypeMapper” />
有几个方便的方法 MongoTemplate
来保存和插入你的对象。为了对转换过程有更精细的控制,你可以使用MappingMongoConverter
例如 Converter<Person, DBObject>
and 来注册Spring转换器 Converter<DBObject, Person>
。
![]() | 注意 |
---|---|
插入和保存操作之间的区别在于,如果对象不存在,则保存操作将执行插入操作。 |
使用保存操作的简单情况是保存一个POJO。在这种情况下,集合名称将由班级名称(未完全满足)确定。您也可以使用特定的集合名称来调用保存操作。可以使用映射元数据覆盖存储对象的集合。
插入或保存时,如果未设置Id属性,则假定其值将由数据库自动生成。因此,对于自动生成的的ObjectId的成功在您的类ID属性/字段的类型必须是String
,ObjectId
或 BigInteger
。
以下是使用保存操作并检索其内容的基本示例。
例4.13。使用MongoTemplate插入和检索文档
import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Criteria.query; ... 人p = 新人(“鲍勃”,33); mongoTemplate.insert(P); 人QP = mongoTemplate.findOne(查询(其中(“年龄”)。是(33)),人。类);
下面列出了您可以使用的插入/保存操作。
-
void
保存(Object objectToSave)
将对象保存到默认的集合。 -
void
保存(Object objectToSave, String collectionName)
将对象保存到指定的集合。
下面列出了一组类似的插入操作
-
void
插入(Object objectToSave)
插入对象的默认集合。 -
void
插入(Object objectToSave, String collectionName)
插入对象到指定的集合。
有两种方法来管理用于在文档上操作的集合名称。使用的默认集合名称是更改为以小写字母开头的类名称。所以一个 com.test.Person
班级将存储在“人员”集合中。您可以通过使用@Document注释提供不同的集合名称来自定义该属性。您也可以通过提供您自己的集合名称作为所选MongoTemplate方法调用的最后一个参数来覆盖集合名称。
MongoDB驱动程序支持在一个操作中插入一组文档。下面列出了MongoOperations接口中支持该功能的方法
-
插入
-
insertAll以一个
Collection
对象作为第一个参数。此方法检查每个对象,并根据上面指定的规则将其插入到适当的集合中。 -
保存保存对象覆盖可能存在的任何对象具有相同的ID。
对于更新,我们可以选择更新使用MongoOperation
方法 找到的第一个文档, updateFirst
或者我们可以使用该方法更新找到的与查询匹配的所有文档updateMulti
。这里是一个更新所有储蓄账户的例子,我们将使用$inc
操作员向余额添加一次$ 50.00的奖金。
例4.14。使用MongoTemplate更新文档
import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Query; import static org.springframework.data.mongodb.core.query.Update; ... WriteResult wr = mongoTemplate.updateMulti(new Query(where(“accounts.accountType”).is(Account.Type.SAVINGS)), new Update().inc(“accounts. $。balance ”,50.00), 帐户。类);
除了Query
上面讨论的,我们还提供了使用Update
对象的更新定义。该Update
班有匹配供MongoDB的更新改进剂的方法。
正如你所看到的,大多数方法返回的 Update
对象为API提供流畅的样式。
Update类可以使用一点“语法糖”,因为它的方法是链接在一起的,你可以通过静态方法public static Update update(String key, Object value)
和静态导入来启动一个新的Update实例的创建 。
以下是Update类中的方法列表
-
Update
addToSet(String key, Object value)
使用$addToSet
更新修改器更新 -
Update
inc(String key, Number inc)
使用$inc
更新修改器进行更新 -
Update
弹出(String key, Update.Position pos)
使用$pop
更新修改器进行更新 -
Update
拉(String key, Object value)
更新使用$pull
更新修改器 -
Update
pullAll(String key, Object[] values)
使用$pullAll
更新修改器进行更新 -
Update
(String key, Object value)
使用$push
更新修改器推送 更新 -
Update
pushAll(String key, Object[] values)
使用$pushAll
更新修改器进行更新 -
Update
(String oldName, String newName)
使用$rename
更新修改器重命名 更新 -
Update
(String key, Object value)
使用$set
更新修改器设置 更新 -
Update
(String key)
使用$unset
更新修改器取消设置 更新
与执行updateFirst
操作相关,也可以执行一个upsert操作,如果找不到与查询匹配的文档,将执行插入操作。插入的文档是查询文档和更新文档的组合。这是一个例子
(“”)是(1111)和(“firstName”)是(“Joe”)和(“Fraizer”)是(“Update”)),update(“地址“,addr),Person.class);
findAndModify(…)
DBCollection上的方法可以更新文档,并在单个操作中返回旧的或新更新的文档。 MongoTemplate
提供了findAndModify方法,它Query
和 Update
类和从转换 DBObject
到你的POJO。这里是方法
<T> T findAndModify(查询查询,更新更新,Class <T> entityClass); <T> T findAndModify(查询查询,更新更新,Class <T> entityClass,String collectionName); findAndModify(查询查询,更新更新,FindAndModifyOptions选项,Class <T> entityClass); <T> T findAndModify(查询查询,更新更新,FindAndModifyOptions选项,Class <T> entityClass,String collectionName);
作为一个例子,我们将插入一些 Person
对象到容器中,并执行一个简单的findAndUpdate操作
mongoTemplate.insert(new Person(“Tom”,21)); mongoTemplate.insert(新人(“Dick”,22)); mongoTemplate.insert(new Person(“Harry”,23)); Query query = new Query(Criteria.where(“firstName”).is(“Harry”)); 更新update = new Update().inc(“age”,1); 人员P = mongoTemplate.findAndModify(查询,更新,人。类); //返回老人对象 assertThat(p.getFirstName(),是(“Harry”)); assertThat(p.getAge(),is(23)); P = mongoTemplate.findOne(查询,人。类); assertThat(p.getAge(),is(24)); 更新时//现在返回新更新的文档 P = template.findAndModify(查询,更新,新 FindAndModifyOptions()returnNew(真),人。类); assertThat(p.getAge(),is(25));
将FindAndModifyOptions
允许您设置returnNew,UPSERT的选项,并删除。下面显示了一个扩展前面的代码snippit的例子
Query query2 = new Query(Criteria.where(“firstName”).is(“Mary”)); P = mongoTemplate.findAndModify(QUERY2,更新,新 FindAndModifyOptions()returnNew(真).upsert(真),人。类); assertThat(p.getFirstName(),is(“Mary”)); assertThat(p.getAge(),is(1));
你可以表达使用您的疑问Query
和Criteria
它具有反映本地的MongoDB运营商的名称,如方法名称类lt
, lte
,is
,等。在 Query
和Criteria
类遵循流畅API样式,以便同时具有易于理解的代码,你可以很容易地串联多个方法标准和查询在一起。Java中的静态导入用于帮助消除为创建Query
和 Criteria
实例查看“新”关键字的需求,从而提高可读性。如果你想Query
从一个普通的JSON字符串使用创建实例BasicQuery
。
例4.15。从普通的JSON字符串创建一个查询实例
BasicQuery query = new BasicQuery(“{age:{$ lt:50},accounts.balance:{$ gt:1000.00}}”); 列表<人>结果= mongoTemplate.find(查询,人类);
GeoSpatial查询也受支持,在“ 地理空间查询 ”一节中对其进行了更详细的描述。
还支持Map-Reduce操作,在Map-Reduce一节中将对此进行更详细的介绍。
在前面的部分中,我们看到了如何使用MongoTemplate上的findOne和findById方法检索单个文档,这些方法返回单个域对象。我们还可以查询要作为域对象列表返回的文档集合。假设我们有一个Person对象,其名称和年龄作为一个集合中的文档存储,并且每个人都有一个带有余额的嵌入式帐户文档。我们现在可以使用以下代码运行查询。
例4.16。使用MongoTemplate查询文档
import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Query.query; ... List <Person> result = mongoTemplate.find(query(where(“age”).lt(50) .and(“accounts.balance”).gt(1000.00d)),Person。类);
所有查找方法都将一个Query
对象作为参数。该对象定义了用于执行查询的标准和选项。条件是使用Criteria
具有名为where
用于实例化新 Criteria
对象的静态工厂方法的对象来指定的 。我们建议使用静态导入的 org.springframework.data.mongodb.core.query.Criteria.where
和Query.query
,使查询更具可读性。
该查询应返回Person
符合指定条件的对象列表。这个 Criteria
类有以下与MongoDB中提供的运算符相对应的方法。
正如你所看到的,大多数方法返回的 Criteria
对象为API提供流畅的样式。
-
Criteria
全部(Object o)
使用$all
操作员创建一个标准 -
Criteria
并将 指定(String key)
的链接添加 到当前 并返回新创建的链接Criteria
key
Criteria
-
Criteria
andOperator(Criteria... criteria)
使用$and
运算符为所有提供的条件创建和查询 (需要MongoDB 2.0或更高版本) -
Criteria
elemMatch(Criteria c)
使用$elemMatch
操作符创建一个标准 -
Criteria
存在(boolean b)
使用$exists
操作符创建一个标准 -
Criteria
gt(Object o)
使用$gt
操作符创建一个标准 -
Criteria
gte(Object o)
使用$gte
操作符创建一个标准 -
Criteria
in(Object... o)
使用$in
运算符为varargs参数创建一个标准。 -
Criteria
in(Collection<?> collection)
使用$in
操作符使用集合创建一个标准 -
Criteria
是(Object o)
使用$is
操作员创建一个标准 -
Criteria
LT(Object o)
创建使用的标准$lt
操作者 -
Criteria
lte(Object o)
使用$lte
操作符创建一个标准 -
Criteria
mod(Number value, Number remainder)
使用$mod
操作符创建一个标准 -
Criteria
ne(Object o)
使用$ne
操作员创建一个标准 -
Criteria
nin(Object... o)
使用$nin
操作符创建一个标准 -
Criteria
norOperator(Criteria... criteria)
使用$nor
运算符为所有提供的条件创建或查询 -
Criteria
不是()
使用$not
直接影响子句的元运算符创建一个标准 -
Criteria
orOperator(Criteria... criteria)
使用$or
运算符为所有提供的条件创建或查询 -
Criteria
正则表达式(String re)
使用a创建一个标准$regex
-
Criteria
大小(int s)
使用$size
操作符创建一个标准 -
Criteria
类型(int t)
使用$type
操作符创建一个标准
Criteria类还有地理空间查询方法。这里是一个列表,但看看地理空间查询部分看到他们在行动。
-
Criteria
withinCenter(Circle circle)
使用$within $center
操作符创建地理空间标准 -
Criteria
withinCenterSphere(Circle circle)
使用$within $center
运算符创建地理空间标准。这仅适用于MongoDB 1.7及更高版本。 -
Criteria
withinBox(Box box)
使用$within $box
操作 创建地理空间标准 -
Criteria
near(Point point)
使用$near
操作创建地理空间标准 -
Criteria
nearSphere(Point point)
使用$nearSphere$center
操作创建地理空间标准。这仅适用于MongoDB 1.7及更高版本。 -
Criteria
maxDistance(double maxDistance)
使用该$maxDistance
操作创建地理空间标准,用于$ near。
该Query
班有用于提供查询选项的一些其他方法。
查询方法需要指定将被返回的目标类型T,并且对于应该对返回类型所指示的集合以外的集合进行操作的查询,它们也被重载并具有显式集合名称。
-
findAll Query从集合中获取T类型对象的列表。
-
findOne将集合上的即席查询的结果映射到指定类型的对象的单个实例。
-
findById返回给定的id和目标类的对象。
-
查找将集合上的即席查询的结果映射到指定类型的列表。
-
findAndRemove将集合上的即席查询的结果映射到指定类型的对象的单个实例。与查询匹配的第一个文档将返回并从数据库中的集合中删除。
MongoDB的支持通过使用等运营商的地理空间查询$near
,$within
和 $nearSphere
。Criteria
该类可以使用特定于地理空间查询的方法。也有一些形状类,Box
, Circle
,和Point
那些与地理信息相关的配合使用 Criteria
方法。
为了理解如何执行GeoSpatial查询,我们将使用以下从集成测试中获取的Venue类,它依赖于使用富集MappingMongoConverter
。
@Document(collection =“newyork”) public class Venue { @Id 私人字符串ID; 私人字符串名称; 私人 双 []位置; @PersistenceConstructor Venue(String name, double [] location){ super(); 这个 .name = name; 这个 .location = location; } public Venue(String name,double x,double y){ super(); 这个 .name = name; 这个 .location = new double [] {x,y}; } public String getName(){ return name; } public double [] getLocation(){ return location; } @Override public String toString(){ return “Venue [id =” + id + “,name =” + name + “,location =” + Arrays.toString(location)+ “]” ; } }
要在a中查找位置Circle
,可以使用以下查询。
圈圈= 新圈( - 73.99171,40.738868,0.01); 列表<Venue> venues = template.find(新查询(Criteria.where( “ 所在地”).withinCenter(圆圈)),地点。类);
要Circle
使用球形坐标查找场地,可以使用以下查询
圈圈= 新圈( - 73.99171,40.738868,0.003712240453784); 列表<Venue> venues = template.find(新查询(Criteria.where( “ 所在地”).withinCenterSphere(圆圈)),地点。类);
Box
在下面的查询中可以使用查找场地
//左下然后右上 箱盒= 新盒(新点( - 73.99756,40.73083),新点( - 73.988135,40.741404)); 列表<Venue> venues = template.find(新查询(Criteria.where( “ 所在地”).withinBox(盒)),地点。类);
要找到附近的场地Point
,可以使用以下查询
点点= 新点( - 73.99171,40.738868); 列表<Venue> venues = template.find(新查询(Criteria.where( “ 所在地”).near(点).maxDistance(0.01)),地点。类);
要找到Point
使用球形坐标附近的场地,可以使用以下查询
点点= 新点( - 73.99171,40.738868); 列表<Venue> venues = template.find(new Query( Criteria.where(“location”).nearSphere(point).maxDistance(0.003712240453784)), 地点。类);
MongoDB支持查询数据库中的地理位置,并同时计算与给定源的距离。使用地理附近查询,可以表达如下查询:“查找周围10英里内的所有餐馆”。这样做MongoOperations
提供了 geoNear(…)
方法 NearQuery
作为参数以及已经熟悉的实体类型和集合
点位置= 新点( - 73.99171,40.738868); NearQuery query = NearQuery.near(location).maxDistance(new Distance(10,Metrics.MILES)); GeoResults <餐厅> = operations.geoNear(查询,餐厅。类);
正如您所看到的,我们使用NearQuery
构建器API来设置一个查询,以返回Restaurant
给定范围内Point
的所有 实例 最多10英里。Metrics
这里使用的 枚举实际上实现了一个接口,以便其他度量也可以插入到一个距离。A Metric
由乘法器支持将给定度量的距离值转换为本地距离。这里显示的示例将认为10英里。使用预先建好的指标之一(英里和公里)将自动触发在查询上设置球形标志。如果你想避免这种情况,只需简单地将 double
值输入maxDistance(…)
。欲了解更多信息,请参阅的JavaDoc中NearQuery
和 Distance
。
接近操作的地理位置返回GeoResults
封装GeoResult
实例的 封装器对象 。包装 GeoResults
允许访问所有结果的平均距离。一个GeoResult
对象只是简单地把找到的实体加上它与原点的距离。
您可以使用Map-Reduce查询MongoDB,这对于批处理,数据聚合以及查询语言何时不满足您的需求非常有用。
Spring通过在MongoOperations上提供方法来提供与MongoDB的map reduce的集成,以简化Map-Reduce操作的创建和执行。它可以将一个Map-Reduce操作的结果转换为一个POJO,同时也集成了Spring的资源抽象抽象。这将使您可以将JavaScript文件放在文件系统,类路径,http服务器或任何其他Spring资源实现上,然后通过简单的URI风格语法(例如“classpath:reduce.js;”)引用JavaScript资源。在文件中对JavaScript代码进行外部化通常比将代码嵌入到Java代码中更可取。请注意,如果您愿意,仍然可以将JavaScript代码作为Java字符串传递。
要理解如何执行Map-Reduce操作,请使用“MongoDB - 权威指南”中的示例。在这个例子中,我们将创建三个具有值[a,b],[b,c]和[c,d]的文档。每个文档中的值都与键“x”相关联,如下所示。对于这个例子,假设这些文档在名为“jmr1”的集合中。
{“_id”:ObjectId(“4e5ff893c0277826074ec533”),“x”:[“a”,“b”]} {“_id”:ObjectId(“4e5ff893c0277826074ec534”),“x”:[“b”,“c”]} {“_id”:ObjectId(“4e5ff893c0277826074ec535”),“x”:[“c”,“d”]}
下面显示了一个映射函数,用于统计每个文档中每个字母的出现情况
function(){ for(var i = 0 ; i < this .x.length; i ++){ 发出(这个 .x [i],1); } }
下面显示了将所有文档中每个字母的出现总结的缩小功能
函数(键,值){ var sum = 0 ; for(var i = 0 ; i <values.length; i ++) sum + = values [i]; 归还金额 }
执行此操作将导致如下所示的集合。
{“_id”:“a”,“value”:1} {“_id”:“b”,“value”:2} {“_id”:“c”,“value”:2} {“_id”:“d”,“value”:1}
假设map和reduce函数位于map.js和reduce.js中并捆绑在您的jar中以便它们在类路径中可用,您可以执行map-reduce操作并获得如下所示的结果
MapReduceResults <的ValueObject>结果= mongoOperations.mapReduce(“jmr1” , “类路径:map.js” , “类路径:reduce.js” 。,的ValueObject 类); for(ValueObject valueObject:results){ 的System.out.println(的ValueObject); }
上面的代码的输出是
ValueObject [id = a,value = 1.0] ValueObject [id = b,value = 2.0] ValueObject [id = c,value = 2.0] ValueObject [id = d,value = 1.0]
MapReduceResults类实现Iterable
并提供对原始输出的访问,以及定时和计数统计。该 ValueObject
班是根本
公共 类 ValueObject { 私人字符串ID; 私人 浮动价值; public String getId(){ return id; } 公共 浮动 getValue(){ 返回值; } public void setValue(float value){ this .value = value; } @Override public String toString(){ return “ValueObject [id =” + id + “,value =” + value + “]” ; } }
默认情况下,使用INLINE的输出类型,因此您不必指定输出集合。要指定其他map-reduce选项,请使用带有附加MapReduceOptions
参数的重载方法 。该类 MapReduceOptions
有一个流畅的API,所以添加额外的选项可以用一个非常简洁的语法来完成。这里是一个将输出集合设置为“jmr1_out”的示例。请注意,仅设置输出集合假设默认输出类型为REPLACE。
MapReduceResults <的ValueObject>结果= mongoOperations.mapReduce(“jmr1” , “类路径:map.js” , “类路径:reduce.js” , 新的。MapReduceOptions()outputCollection(“jmr1_out” 。),的ValueObject 类);
还有一个静态导入import static org.springframework.data.mongodb.core.mapreduce.MapReduceOptions.options;
可以用来使语法稍微紧凑
MapReduceResults <ValueObject> results = mongoOperations.mapReduce(“jmr1”,“classpath:map.js”,“classpath:reduce.js”, options()。outputCollection(“jmr1_out”),ValueObject。类);
您还可以指定一个查询来减少将用于提供给map-reduce操作的数据集。这将从包含[a,b]的文件中删除map-reduce操作。
Query query = new Query(where(“x”).ne(new String [] { “a”,“b” })); MapReduceResults <ValueObject> results = mongoOperations.mapReduce(query,“jmr1”,“classpath:map.js”,“classpath:reduce.js”, options()。outputCollection(“jmr1_out”),ValueObject。类);
请注意,您也可以在查询中指定其他限制值和排序值,但不能跳过值。
作为替代使用的map-reduce进行数据汇总,您可以使用group
操作这感觉类似于使用SQL的group by查询的风格,所以它可能会觉得更加平易近人与使用的map-reduce。使用组操作确实有一些限制,例如它在共享环境中不受支持,并且它将在一个BSON对象中返回完整的结果集,所以结果应该很小,小于10,000个键。
Spring通过在MongoOperations上提供方法来提供与MongoDB组操作的集成,以简化组操作的创建和执行。它可以将组操作的结果转换为POJO,也可以与Spring的资源抽象抽象相结合。这将使您可以将JavaScript文件放在文件系统,类路径,http服务器或任何其他Spring资源实现上,然后通过简单的URI风格语法(例如“classpath:reduce.js;”)引用JavaScript资源。在文件中对JavaScript代码进行外部化(如果经常更喜欢将它们作为Java字符串嵌入到代码中)。请注意,如果您愿意,仍然可以将JavaScript代码作为Java字符串传递。
为了理解群体操作是如何工作的,使用了下面的例子,这是有些人为的。更实际的例子请参考“MongoDB - 权威指南”一书。使用以下行创建一个名为“group_test_collection”的集合。
{“_id”:ObjectId(“4ec1d25d41421e2015da64f1”),“x”:1} {“_id”:ObjectId(“4ec1d25d41421e2015da64f2”),“x”:1} {“_id”:ObjectId(“4ec1d25d41421e2015da64f3”),“x”:2} {“_id”:ObjectId(“4ec1d25d41421e2015da64f4”),“x”:3} {“_id”:ObjectId(“4ec1d25d41421e2015da64f5”),“x”:3} {“_id”:ObjectId(“4ec1d25d41421e2015da64f6”),“x”:3}
我们想按照每一行中唯一的字段进行分组,'x'字段并且聚合每个'x'的特定值出现的次数。要做到这一点,我们需要创建一个包含我们的count变量的初始文档,还有一个reduce函数,每次遇到这个函数都会增加它。执行组操作的Java代码如下所示
GroupByResults <XObject> results = mongoTemplate.group(“group_test_collection”, GroupBy.key(“x”).initialDocument(“{count:0}”).reduceFunction(“function(doc,prev){prev.count + = 1}”) X对象。类);
第一个参数是要运行组操作的集合的名称,第二个参数是流畅的API,通过GroupBy
类指定组操作的属性。在这个例子中,我们只使用intialDocument
和reduceFunction
方法。您也可以指定一个键函数,以及一个终结器作为流利API的一部分。如果您有多个要分组的键,则可以传递逗号分隔的键列表。
组操作的原始结果是一个像这样的JSON文档
{ “retval”:[{“x”:1.0,“count”:2.0}, {“x”:2.0,“count”:1.0}, {“x”:3.0,“count”:3.0}], “count”:6.0, “钥匙”:3, “好”:1.0 }
“retval”字段下的文档映射到组方法中的第三个参数,在这种情况下,XObject如下所示。
公共 类 XObject { 私人 浮动 x; 私人 浮动计数; public float getX(){ return x; } public void setX(float x){ this .x = x; } public float getCount(){ return count; } public void setCount(float count){ this .count = count; } @Override public String toString(){ return “XObject [x =” + x + “count =” + count + “]” ; } }
您还可以得到原始结果为 DbObject
通过调用方法 getRawResults
的 GroupByResults
类。
组方法的另一个重载方法 MongoOperations
是让你指定一个 Criteria
对象来选择行的一个子集。下面显示了一个Criteria
使用静态导入的一些语法糖的对象,以及通过Spring资源字符串引用一个键函数和减少函数JavaScript文件的例子。
import static org.springframework.data.mongodb.core.mapreduce.GroupBy.keyFunction; import static org.springframework.data.mongodb.core.query.Criteria.where; GroupByResults <XObject> results = mongoTemplate.group(where(“x”)。gt(0), “group_test_collection” keyFunction(“classpath:keyFunction.js”)。initialDocument(“{count:0}”)。reduceFunction(“classpath:groupReduce.js”),XObject.class);
Spring Data MongoDB支持在2.2版本中引入MongoDB的Aggregation Framework。
MongoDB文档描述的聚合框架如下:“ MongoDB聚合框架提供了一种计算聚合值而不必使用map-reduce的方法。虽然map-reduce功能强大,但对于许多简单的聚合任务来说,通常比完成或平均字段值更困难。”
有关更多信息,请参阅MongoDB的聚合框架和其他数据聚合工具的完整参考文档。
在Spring数据MongoDB中的聚合框架的支持是基于以下关键抽象Aggregation
, AggregationOperation
和 AggregationResults
。
-
Aggregation
聚合代表一个MongoDB
aggregate
操作,并持有聚合管道指令的描述。聚合是通过调用适当的newAggregation(…)
静态工厂Aggregation
类的方法 来创建的,它将 列表AggregateOperation
作为可选输入类旁边的参数。实际的集合操作是通过也将所需的输出类作为参数的
aggregate
方法 来执行的MongoTemplate
。 -
AggregationOperation
An
AggregationOperation
表示一个MongoDB聚合流水线操作,并描述了在这个聚合步骤中应该执行的处理。尽管可以手动创建一个AggregationOperation
推荐的构造AggregateOperation
方法,但是可以使用Aggregate
该类提供的静态工厂方法。 -
AggregationResults
AggregationResults
是集合操作结果的容器。它以一种形式提供对原始聚合结果的访问,DBObject
以及对执行聚合的映射对象和信息的访问。
使用MongoDB Aggregation Framework的Spring Data MongoDB支持的规范示例如下所示:
import static org.springframework.data.mongodb.core.aggregation.Aggregation。*; 聚合agg = newAggregation( pipelineOP1() pipelineOP2() pipelineOPn() ); AggregationResults <输出类型>结果= mongoTemplate.aggregate(AGG,“INPUT_COLLECTION_NAME” ,输出类型。类); List <OutputType> mappedResult = results.getMappedResults();
请注意,如果您提供输入类作为该newAggregation
方法 的第一个参数,那么MongoTemplate
将从此类派生输入集合的名称。否则,如果您不指定输入类,则必须明确提供输入集合的名称。如果提供输入类和输入集合,则后者优先。
MongoDB聚合框架提供了以下类型的聚合操作:
-
流水线聚合算子
-
组合运算符
-
布尔聚合运算符
-
比较汇总运算符
-
算术聚合算子
-
字符串聚合操作符
-
日期汇总运算符
-
条件聚合算子
在撰写本文时,我们提供了对Spring Data MongoDB中以下聚合操作的支持。
表4.1。Spring Data MongoDB目前支持聚合操作
流水线聚合算子 | 项目,跳过,限制,放松,组,排序,地理接近 |
组合运算符 | addToSet,first,last,max,min,avg,push,sum,(* count) |
算术聚合算子 | 加(*通过加),减(*通过减),乘,除,mod |
比较汇总运算符 | eq(* via:是),gt,gte,lt,lte,ne |
请注意,Spring Data MongoDB目前不支持此处未列出的聚合操作。比较聚合运算符用Criteria
表达式表示。
*)该操作由Spring Data MongoDB映射或添加。
投影表达式用于定义作为特定聚合步骤结果的字段。投影表达式可以通过类的project
方法 来定义Aggregate
。
例4.17。投影表达的例子
项目(“name”,“netPrice”)//将生成{$ project:{name:1,netPrice:1}} 项目()和(“foo”).as(“bar”)//将生成{ $项目:{栏:$ foo的}} 项目(“A” , “b” )。而(“foo”的)。如(“栏”)//将产生{$项目:{A:1,b:1 ,bar:$ foo}}
请注意,AggregationTests
课堂上可以找到更多的项目操作示例。
请注意,有关投影表达式的更多细节可以在MongoDB Aggregation Framework参考文档的相应部分找到。
从版本1.4.0开始,我们支持通过类的andExpression
方法在投影表达式中使用SpEL表达式ProjectionOperation
。这使您可以将所需的表达式定义为SpEL表达式,并在查询执行时将其转换为相应的MongoDB投影表达式部分。这使得表达复杂的计算变得更容易。
例4.18。用SpEL表达式进行复杂的计算
以下SpEL表达式:
1 +(q + 1)/(q- 1)
将被翻译成下面的投影表达式部分:
{ “$ add”:[ 1,{ “$ divide”:[{ “$ add”:[ “$ q”,1 ]},{ “$ subtract”:[ “$ q”,1 ]} ] }]}
在例4.23“聚合框架示例5”和例4.24“聚合框架示例6”中的更多上下文中查看一个示例。您可以在中找到更多用于支持SpEL表达式结构的使用示例SpelExpressionTransformerUnitTests
。
以下示例演示了MongoDB Aggregation Framework与Spring Data MongoDB的使用模式。
例4.19。聚合框架示例1
在这个介绍性的例子中,我们想要聚合一个标签列表,以便从"tags"
发生次数降序的MongoDB集合中获取特定标签的出现次数。这个例子演示了分组,排序,投影(选择)和展开(结果分割)的用法。
类 TagCount { 字符串标签; int n; }
import static org.springframework.data.mongodb.core.aggregation.Aggregation。*; 聚合agg = newAggregation( 项目(“标签”), 展开(“标签”), group(“tags”).count()。as(“n”), 项目(“n”)和(“标记”).previousOperation(), 排序(DESC,“n”) ); AggregationResults <TagCount>结果= mongoTemplate.aggregate(AGG, “ 标签”,TagCount。类); List <TagCount> tagCount = results.getMappedResults();
-
为了做到这一点,我们首先通过
newAggregation
静态工厂方法创建一个新的聚合 ,我们传递一个聚合操作列表。这些聚合操作定义了我们的聚合管道Aggregation
。 -
作为第二步,我们
"tags"
从操作的输入集合中选择字段(这是一个字符串数组)project
。 -
在第三步中,我们使用该
unwind
操作为"tags"
阵列中的每个标签生成一个新的文档 。 -
在第四步中,我们使用
group
操作为每个"tags"
值定义一个组,通过count
聚合运算符来聚合发生次数 ,并将结果收集到一个名为的新字段中"n"
。 -
作为第五步,我们选择该字段,
"n"
并为之前的组操作(因此调用previousOperation()
)生成的id字段的名称创建一个别名"tag"
。 -
作为第六步,我们通过
sort
操作将得到的标签列表按其出现次数降序排列 。 -
最后,我们调用
aggregate
MongoTemplate上的Method来让MongoDB以创建Aggregation
的参数执行acutal聚合操作 。
请注意,输入集合被显式指定为 Method 的 "tags"
参数aggregate
。如果未明确指定输入集合的名称,则它是从作为newAggreation
Method的第一个参数传入的输入类派生的 。
例4.20。聚合框架示例2
这个例子是基于MongoDB Aggregation Framework文档中最大和最小的城邦州例子。我们增加了额外的排序来产生不同的MongoDB版本的稳定的结果。在这里,我们想要使用聚合框架,按照每个州的人口来返回最小和最大的城市。这个例子演示了分组,排序和预测(选择)的用法。
类 ZipInfo { 字符串ID; 弦乐城; 字符串状态; @Field(“pop”) int population; @Field(“loc”) double []位置; } class City { 字符串名称; 整体人口 } 类 ZipInfoStats { 字符串ID; 字符串状态; 市最大的城市; 城市最小城市; }
import static org.springframework.data.mongodb.core.aggregation.Aggregation。*; TypedAggregation <ZipInfo>聚集= newAggregation(ZipInfo。类, 组(“国家”,“城市”) .sum(“population”). as(“ pop”), 排序(ASC,“流行”,“国家”,“城市”), 组(“国家”) .last(“city”). as(“largestCity”) .last(“pop”). as(“ largestPop ”) .first(“city”).as(“smallestCity”) .first(“pop”).as(“smallestPop”), 项目() .and(“state”).previousOperation() 和(“最大的城市”) .nested(bind(“name”,“largestCity”)和(“population”,“largestPop”)) .and(“smallestCity”) .nested(bind(“name”,“smallestCity”)和(“population”,“smallestPop”)), 排序(ASC,“国家”) ); AggregationResults <ZipInfoStats>结果= mongoTemplate.aggregate(聚集,ZipInfoStats。类); ZipInfoStats firstZipInfoStats = result.getMappedResults()。get(0);
-
该类
ZipInfo
映射给定输入集合的结构。该类ZipInfoStats
以所需的输出格式定义结构。 -
作为第一步,我们使用该
group
操作从输入集合中定义一个组。分组标准是字段的组合"state"
并且"city"
形成组的id结构。我们"population"
通过使用sum
运算符将结果保存在字段中,从分组的元素中聚合属性的值"pop"
。 -
在第二步中,我们使用
sort
操作按字段对中间结果进行排序"pop"
,"state"
并按"city"
升序排列,使得最小的城市位于最上方,最大的城市位于结果的最下方。请注意,对“状态”的排序"city"
是针对Spring Data MongoDB处理的组ID字段隐式执行的。 -
在第三步中,我们
group
再次使用一个操作来将中间结果分组"state"
。请注意,"state"
再次隐式引用一个group-id字段。我们通过操作分别选择最大和最小的城市的名字和人口统计与调用last(…)
和first(...)
运算符project
。 -
作为第四步,我们
"state"
从前面的group
操作中选择字段。请注意,"state"
再次隐式引用一个group-id字段。由于我们不想隐式生成的id出现,我们通过以前的操作排除idand(previousOperation()).exclude()
。由于我们要City
在我们的输出类中填充嵌套结构,我们必须使用嵌套方法发出适当的子文档。 -
最后,作为第五步,我们
StateStats
通过sort
操作升序排列结果列表的 状态名称。
请注意,我们从ZipInfo
作为第一个参数传递给newAggregation
-Method 的-class 派生了input-collection的名称 。
例4.21。聚合框架示例3
这个例子是基于MongoDB Aggregation Framework文档中有超过一千万个例子的国家。我们增加了额外的排序来产生不同的MongoDB版本的稳定的结果。在这里,我们要使用聚合框架返回人口超过1000万的所有州。这个例子演示了分组,排序和匹配(过滤)的用法。
class StateStats { @Id String id; 字符串状态; @Field(“totalPop”) int totalPopulation; }
import static org.springframework.data.mongodb.core.aggregation.Aggregation。*; TypedAggregation <ZipInfo> AGG = newAggregation(ZipInfo。类, group(“state”).sum(“population”). as(“totalPop”), 排序(ASC,previousOperation(),“totalPop”), match(where(“totalPop”).gte(10 * 1000 * 1000)) ); AggregationResults <StateStats>结果= mongoTemplate.aggregate(AGG,StateStats。类); 列表<StateStats> stateStatsList = result.getMappedResults();
-
作为第一步,我们将输入集合按
"state"
字段进行分组, 并计算字段的总和"population"
并将结果存储在新字段中"totalPop"
。 -
在第二步中,除了
"totalPop"
字段的升序外,我们还通过前面的组操作的id-reference对中间结果进行 排序。 -
最后,在第三步中,我们使用
match
接受Criteria
查询作为参数的操作来 过滤中间结果。
请注意,我们从ZipInfo
作为第一个参数传递给newAggregation
-Method 的-class 派生了input-collection的名称 。
例4.22。聚合框架示例4
这个例子演示了在投影操作中使用简单的算术运算。
class产品{ 字符串ID; 字符串名称; 双 netPrice; int spaceUnits; }
import static org.springframework.data.mongodb.core.aggregation.Aggregation。*; TypedAggregation <产品> AGG = newAggregation(产品。类, 项目(“名称”,“netPrice”) .and(“netPrice”).plus(1).as(“netPricePlus1”) .and(“netPrice”).minus(1).as(“netPriceMinus1”) .and(“netPrice”).multiply(1.19).as(“grossPrice”) .and(“netPrice”).divide(2).as(“netPriceDiv2”) .and(“spaceUnits”). mod(2).as(“spaceUnitsMod2”) ); AggregationResults <DBOBJECT>结果= mongoTemplate.aggregate(AGG,DBOBJECT。类); List <DBObject> resultList = result.getMappedResults();
请注意,我们从Product
作为第一个参数传递给newAggregation
-Method 的-class 派生了input-collection的名称 。
例4.23。聚合框架示例5
本例演示了在投影操作中使用从SpEL表达式派生的简单算术运算。
class产品{ 字符串ID; 字符串名称; 双 netPrice; int spaceUnits; }
import static org.springframework.data.mongodb.core.aggregation.Aggregation。*; TypedAggregation <产品> AGG = newAggregation(产品。类, 项目(“名称”,“netPrice”) .andExpression(“netPrice + 1”). as(“netPricePlus1”) .andExpression(“netPrice - 1”). as(“netPriceMinus1”) .andExpression(“netPrice / 2”). as(“netPriceDiv2”) .andExpression(“netPrice * 1.19”). as(“grossPrice”) .andExpression(“spaceUnits%2”). as(“spaceUnitsMod2”) .andExpression(“(netPrice * 0.8 + 1.2)* 1.19”). as(“grossPriceIncludingDiscountAndCharge”) ); AggregationResults <DBOBJECT>结果= mongoTemplate.aggregate(AGG,DBOBJECT。类); List <DBObject> resultList = result.getMappedResults();
例4.24。聚合框架示例6
这个例子演示了在投影操作中使用从SpEL表达式导出的复杂算术运算。
注意:传递给addExpression
Method 的附加参数 可以通过索引器表达式根据它们的位置来引用。在这个例子中,我们引用shippingCosts
了参数array的第一个参数via的参数[0]
。当SpEL表达式转换为MongoDB聚合框架表达式时,外部参数表达式将被各自的值替换。
class产品{ 字符串ID; 字符串名称; 双 netPrice; int spaceUnits; }
import static org.springframework.data.mongodb.core.aggregation.Aggregation。*; 双运费= 1.2 ; TypedAggregation <产品> AGG = newAggregation(产品。类, 项目(“名称”,“netPrice”) .andExpression(“(netPrice *(1-discountRate)+ [0])*(1 + taxRate)”,shippingCosts).as(“salesPrice”) ); AggregationResults <DBOBJECT>结果= mongoTemplate.aggregate(AGG,DBOBJECT。类); List <DBObject> resultList = result.getMappedResults();
请注意,我们也可以在SpEL表达式中引用文档的其他字段。
为了有更多的细粒度控制映射过程,您可以用注册春季转换器 MongoConverter
实现如 MappingMongoConverter
。
MappingMongoConverter
在尝试映射对象本身之前,检查是否有任何可以处理特定类的Spring转换器。为了“劫持”正常的映射策略MappingMongoConverter
,也许为了提高性能或其他自定义映射需求,首先需要创建Spring Converter
接口的实现, 然后使用MappingConverter进行注册。
![]() | 注意 |
---|---|
有关Spring的类型转换服务的详细信息,请参阅参考文档在这里。 |
下面显示了Converter
从Person对象转换为的示例实现 com.mongodb.DBObject
import org.springframework.core.convert.converter.Converter; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; 公共 类 PersonWriteConverter 实现 Converter <Person,DBObject> { public DBObject convert(Person source){ DBObject dbo = new BasicDBObject(); dbo.put(“ _id ”,source.getId()); dbo.put(“name”,source.getFirstName()); dbo.put(“age”,source.getAge()); 返回 dbo; } }
下面显示了一个从DBObject转换成Person对象的Converter的示例实现
公共 类 PersonReadConverter 实现转换器<DBObject,Person> { public Person convert(DBObject source){ 人员P = 新人((的ObjectId)source.get(“_id” ),(字符串)source.get( “ 名称”)); p.setAge((Integer)source.get(“age”)); 返回 p; } }
Mongo Spring命名空间提供了一种方便的方式来注册Spring的Converter
s MappingMongoConverter
。下面的配置代码展示了如何手动注册转换器bean以及将包装配置MappingMongoConverter
成一个MongoTemplate
。
<mongo:db-factory dbname = “database” /> <mongo:mapping-converter> <mongo:custom-converters> <mongo:converter ref = “readConverter” /> <蒙戈:变换器> <豆 类 = “org.springframework.data.mongodb.test.PersonWriteConverter” /> < / mongo:converter> </ mongo:custom-converters> </ mongo:mapping-converter> <bean id = “readConverter” class = “org.springframework.data.mongodb.test.PersonReadConverter” /> <bean id = “mongoTemplate” class = “org.springframework.data.mongodb.core.MongoTemplate” > <constructor-arg name = “mongoDbFactory” ref = “mongoDbFactory” /> <constructor-arg name = “mongoConverter” ref = “mappingConverter” /> </ bean>
您还可以使用custom-converters元素的base-package属性为所有包Converter
和 GenericConverter
下面的实现启用类路径扫描 。
<mongo:mapping-converter> <mongo:custom-converters base-package = “com.acme。**。converters” /> </ mongo:mapping-converter>
一般来说,我们检查Converter
它们转换来源和目标类型的实现。取决于其中的一个是否是MongoDB可以本地处理的类型,我们将把转换器实例注册为读取或写入。看看下面的例子:
//写转换器只有目标类型是Mongo可以本地处理的 类 MyConverter implements Converter <Person,String> {...} //读取转换器只有源类型是Mongo可以本地处理的 类 MyConverter implements Converter <String,Person> {...}
如果你写Converter
的源和目标类型是本地Mongo类型,我们无法确定是否应该把它看成是读写转换器。将转换器实例注册为两者可能会导致不需要的结果。例如,a Converter<String, Long>
是不明确的,尽管在写作时尝试将所有String
s转换成 Long
s 是没有意义的。通常能够强制基础设施注册一种方式的转换器,只有我们提供 @ReadingConverter
以及 @WritingConverter
在转换器实施中使用。
MongoTemplate
提供了一些管理索引和集合的方法。这些被收集到一个名为helper的接口中IndexOperations
。您可以通过调用方法来访问这些操作,indexOps
并传入集合名称或java.lang.Class
实体(集合名称将通过名称或通过注释元数据从.class派生)。
的IndexOperations
界面如下图所示
公共 接口 IndexOperations { void ensureIndex(IndexDefinition indexDefinition); void dropIndex(String name); void dropAllIndexes(); void resetIndexCache(); List <IndexInfo> getIndexInfo(); }
我们可以在集合上创建一个索引来提高查询性能。
-
ensureIndex确保为集合提供了所提供的IndexDefinition的索引。
您可以使用类创建标准索引和地理空间索引IndexDefinition
和 GeoSpatialIndex
尊敬。例如,给定上一节中定义的Venue类,您将声明如下所示的地理空间查询
mongoTemplate.indexOps(场馆类).ensureIndex(新 GeospatialIndex( “ 位置”));
IndexOperations接口的方法getIndexInfo返回一个IndexInfo对象的列表。这包含在collectcion上定义的所有索引。下面是一个定义具有age属性的Person类的索引的示例。
template.indexOps(人类).ensureIndex(新指数()上(“时代”,Order.DESCENDING).unique(Duplicates.DROP)); 列表<IndexInfo> indexInfoList = template.indexOps(人类).getIndexInfo(); //包含 // [IndexInfo [fieldSpec = {_ id = ASCENDING},name = _id_,unique = false,dropDuplicates = false,sparse = false], // IndexInfo [fieldSpec = {age = DESCENDING},name = age_-1 ,unique = true,dropDuplicates = true,sparse = false]]
现在是时候看一些代码示例,展示如何使用 MongoTemplate
。首先我们看看创建我们的第一个集合。
例4.26。使用MongoTemplate处理集合
DBCollection集合= null; if(!mongoTemplate.getCollectionNames()。contains(“MyNewCollection”)){ collection = mongoTemplate.createCollection(“MyNewCollection”); } mongoTemplate.dropCollection(“MyNewCollection”);
-
getCollectionNames返回一组集合名称。
-
collectionExists检查是否存在具有给定名称的集合。
-
createCollection创建一个不封闭的集合
-
dropCollection删除集合
-
getCollection按名称获取集合,如果不存在则创建集合。
您也可以DB.command( )
使用上的executeCommand(…)
方法获取MongoDB驱动程序的方法MongoTemplate
。这些也将执行到Spring的DataAccessException
层次结构的异常转换 。
内置到MongoDB映射框架中的是几个 org.springframework.context.ApplicationEvent
事件,你的应用程序可以通过注册特殊的bean来响应ApplicationContext
。通过基于Spring的ApplicationContext事件基础结构,这使得其他产品(如Spring集成)能够轻松地接收这些事件,因为它们是基于Spring的应用程序中众所周知的事件机制。
要拦截一个对象,然后再经过转换过程(将你的域对象变成一个com.mongodb.DBObject
),你可以注册一个对象 的子类 AbstractMongoEventListener
来覆盖这个 onBeforeConvert
方法。事件发送时,侦听器将被调用,并在域对象进入转换器之前通过。
例4.27。
公共 类 BeforeConvertListener 扩展 AbstractMongoEventListener <Person> { @Override public void onBeforeConvert(人P){ ...做一些审计操纵,设置时间戳,无论... } }
要在进入数据库之前拦截一个对象,你需要注册一个对象的子类 org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener
来覆盖该onBeforeSave
方法。当事件发送时,您的侦听器将被调用并通过域对象和转换com.mongodb.DBObject
。
例4.28。
公共 类 BeforeSaveListener 扩展 AbstractMongoEventListener <Person> { @Override public void onBeforeSave(人P,DBOBJECT DBO){ ...更改值,删除它们,无论... } }
只要在Spring ApplicationContext中声明这些bean,就会在调度事件时调用它们。
AbstractMappingEventListener中的回调方法列表是
-
onBeforeConvert
- 在使用MongoConveter将对象转换为DBObject之前,调用MongoTemplate insert,insertList和save操作。 -
onBeforeSave
- 在 插入/保存DBObject到数据库之前,调用MongoTemplate insert,insertList和save操作。 -
onAfterSave
- 在数据库中插入/保存DBObject 后,调用MongoTemplate insert,insertList和save操作。 -
onAfterLoad
- 从数据库中检索DBObject之后,在MongoTempnlate中调用find,findAndRemove,findOne和getCollection方法。 -
onAfterConvert
- 在从数据库检索到的DBObject转换为POJO后,调用MongoTempnlate find,findAndRemove,findOne和getCollection方法。
Spring框架为各种数据库和映射技术提供了异常转换。传统上,这是针对JDBC和JPA的。对MongoDB的Spring支持通过提供org.springframework.dao.support.PersistenceExceptionTranslator
接口的实现将这个特性扩展到MongoDB数据库 。
映射到Spring的一致性数据访问异常层次结构的动机是您可以编写可移植和描述性的异常处理代码,而无需依靠MongoDB错误代码进行编码。所有Spring的数据访问异常都是从根DataAccessException
类继承的,所以你可以确定你将能够在一个try-catch块中捕获所有与数据库相关的异常。请注意,MongoDB驱动程序抛出的所有异常并不是从MongoException类继承的。内部异常和消息被保留,所以没有信息丢失。
一些由MongoExceptionTranslator
com.mongodb.Network 执行的映射 为DataAccessResourceFailureException,MongoException
错误代码为1003,12001,12010,12011,12012 InvalidDataAccessApiUsageException
。查看实现以获取更多关于映射的细节。
所有Spring模板类的一个常见设计特征是所有的功能都被路由到一个模板执行回调方法。这有助于确保可能需要的异常和任何资源管理的一致性。虽然JDBC和JMS比MongoDB更需要它,但它仍然为异常转换和日志记录提供了一个单独的位置。因此,使用xe执行回调是访问MongoDB驱动程序DB
和DBCollection
对象来执行非公开操作的首选方法,这些操作并不作为方法公开 MongoTemplate
。
这是一个执行回调方法的列表。
-
<T> T
execute(Class<?> entityClass, CollectionCallback<T> action)
为给定类的实体集合执行给定的CollectionCallback。 -
<T> T
execute(String collectionName, CollectionCallback<T> action)
对给定名称的集合执行给定的CollectionCallback。 -
<T> T
执行(DbCallback<T> action) Spring Data MongoDB provides support for the Aggregation Framework introduced to MongoDB in version 2.2.
根据需要执行翻译任何异常的DbCallback。 -
<T> T
执行(String collectionName, DbCallback<T> action)
对给定名称的集合执行DbCallback,根据需要转换任何异常。 -
<T> T
executeInSession(DbCallback<T> action)
在与数据库相同的连接中执行给定的DbCallback,以确保在写入繁重的环境中可以读取您写入的数据的一致性。
这是一个使用CollectionCallback
返回关于索引的信息的例子
布尔 hasIndex = template.execute( “ 地理定位”,新 CollectionCallbackBoolean>(){ 公共布尔doInCollection(地点。类,DBCollection集合)抛出 MongoException,DataAccessException的{ List <DBObject> indexes = collection.getIndexInfo(); for(DBObject dbo:indexes){ if(“location_2d” .equals(dbo.get(“name”))){ return true; } } 返回 false; } });
MongoDB支持在其文件系统GridFS中存储二进制文件。Spring Data MongoDB提供了一个 GridFsOperations
接口以及相应的实现GridFsTemplate
来轻松地与文件系统进行交互。你可以设置一个 GridFsTemplate
实例被交给它 MongoDbFactory
还有一个 MongoConverter
:
例4.29。用于GridFsTemplate的JavaConfig设置
类 GridFsConfiguration 扩展 AbstractMongoConfiguration { // ...进一步的配置省略 @Bean public GridFsTemplate gridFsTemplate(){ return new GridFsTemplate(mongoDbFactory(),mappingMongoConverter()); } }
相应的XML配置如下所示:
例4.30。GridFsTemplate的XML配置
<?xml version =“1.0”encoding =“UTF-8”?> <beans xmlns = “http://www.springframework.org/schema/beans” xmlns:xsi = “http://www.w3.org / 2001 / XMLSchema-instance“ xmlns:mongo = ”http://www.springframework.org/schema/data/mongo“ xsi:schemaLocation = ”http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd“ > <mongo:db-factory id = “mongoDbFactory” dbname = “database” /> <mongo:mapping-converter id = “converter” /> <bean class = “org.springframework.data.mongodb.gridfs.GridFsTemplate” > <constructor-arg ref = “mongoDbFactory” /> <constructor-arg ref = “converter” /> </ bean> </豆>
现在可以将模板注入并用于执行存储和检索操作。
例4.31。使用GridFsTemplate来存储文件
class GridFsClient { @Autowired GridFsOperations操作; @Test public void storeFileToGridFs { FileMetadata元数据= 新的 FileMetadata(); //填充元数据 资源文件= ... //查找文件或资源 operations.store(file.getInputStream(),“filename.txt”,metadata); } }
这些store(…)
操作需要一个 InputStream
,文件名和可选的有关文件的元数据信息来存储。元数据可以是一个任意的对象,这个对象将会被MongoConverter
配置了的 GridFsTemplate
。或者,您也可以提供一个DBObject
。
从文件系统读取文件可以通过find(…)
或 getResources(…)
方法来实现 。我们先来看看 find(…)
方法。您可以找到匹配一个Query
或多个文件的单个文件。为了方便定义文件查询,我们提供了 GridFsCriteria
帮助类。它提供静态工厂方法来封装默认的元数据字段(例如whereFilename()
,whereContentType()
)或通过自定义的 元数据字段 whereMetaData()
。
例4.32。使用GridFsTemplate来查询文件
class GridFsClient { @Autowired GridFsOperations操作; @Test public void findFilesInGridFs { List <GridFSDBFile> result = operations.find(query(whereFilename()。is(“filename.txt”))) } }
![]() | 注意 |
---|---|
目前MongoDB在从GridFS中检索文件时不支持定义排序标准。因此,在 |
从GridF读取文件的另一个选择是使用ResourcePatternResolver
接口引入的方法。它们允许将Ant路径传递到方法ar中,从而检索与给定模式匹配的文件。