Mongdb学习(五)MongoDB支持(MongoDB支持)(从MongoDB官网谷歌译文)

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

4.1入门

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。

  • 如果构造函数的参数名称与存储文档的字段名称相匹配,则将用于实例化对象

4.2示例存储库

有一个github存储库,有几个例子,你可以下载和玩弄,以了解图书馆是如何工作的。

4.3用Spring连接MongoDB

使用MongoDB和Spring的首要任务之一是com.mongodb.Mongo使用IoC容器创建一个 对象。有两种主要的方法可以使用基于Java的bean元数据或基于XML的bean元数据。这些在下面的章节中讨论。

[注意] 注意

对于那些不熟悉如何使用基于Java bean的元数据,而不是XML来配置Spring容器基于元数据请参阅参考文档的高层次引进这里还有详细的文档 在这里

4.3.1使用基于Java的元数据注册Mongo实例

使用基于的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的容器注册一个实例 实例 MongoFactoryBeancom.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.MongoMongoFactoryBean其他 @Configuration或您自己的类创建对象,请使用“ private @Autowired Mongo mongo;”字段。


4.3.2使用基于XML的元数据注册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” />	   


4.3.3 MongoDbFactory接口

虽然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的使用,并且是入门部分中显示的列表之间的唯一区别

4.3.4使用基于Java的元数据注册MongoDbFactory实例

为了在容器中注册一个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());
  }
}

4.3.5使用基于XML的元数据注册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>

4.4一般审计配置

激活审计功能只是将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

4.5 MongoTemplate简介

该类MongoTemplate位于包中org.springframework.data.document.mongodb,是Spring MongoDB支持的中心类,它提供了一个与数据库交互的丰富功能集。该模板提供了创建,更新,删除和查询MongoDB文档的便利操作,并提供了域对象和MongoDB文档之间的映射。

[注意] 注意

一旦配置,MongoTemplate就是线程安全的,可以在多个实例中重用。

MongoDB文档和域类之间的映射是通过委托给接口的实现来完成的 MongoConverterSpring提供了两种实现方式,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, CriteriaUpdateDBObject

[注意] 注意

引用MongoTemplate实例操作的首选方法 是通过它的接口 MongoOperations

MongoTemplateMongoMappingConverter 使用的默认转换器实现 虽然 MongoMappingConverter可以使用额外的元数据来指定对象到文档的映射,但它也能够通过使用用于映射ID和集合名称的一些约定来转换不包含额外元数据的对象。映射章节解释了这些约定以及映射注释的使用

[注意] 注意

在M2版本中SimpleMappingConverter,是默认的,这个类现在已经被弃用了,因为它的功能被MongoMappingConverter包含了。

MongoTemplate的另一个核心功能是将MongoDB Java驱动程序中抛出的异常异常转换为Spring的可移植数据访问异常层次结构。有关更多信息,请参阅异常翻译部分

MongoTemplate如果您需要直接访问MongoDB驱动程序API以访问MongoTemplate没有明确公开的功能,则可以使用多种Execute回调方法之一来访问底层驱动程序API,但有许多便利方法 可帮助您轻松执行常见任务。执行回调会给你一个com.mongodb.Collection或一个 com.mongodb.DB对象的引用 请参阅执行回调部分 了解更多信息。

现在我们来看一个如何MongoTemplate在Spring容器的上下文中使用的例子 

4.5。实例化MongoTemplate

您可以使用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

[注意] 注意

引用MongoTemplate实例操作的首选方法 是通过它的接口 MongoOperations

WriteResultChecking策略

在开发过程中,如果com.mongodb.WriteResult 从任何MongoDB操作返回的都包含错误,则记录或抛出异常非常方便忘记在开发过程中这样做是很常见的,然后最终得到一个看起来像是成功运行的应用程序,但实际上数据库并没有根据您的期望进行修改。将MongoTemplate的WriteResultChecking属性设置为具有以下值的枚举:LOG,EXCEPTION或NONE,以记录错误,抛出和异常,或者什么也不做。缺省值是使用WriteResultCheckingNONE值。

WriteConcern

如果尚未通过更高级别的驱动程序指定com.mongodb.WriteConcern ,则可以设置MongoTemplate将用于写入操作属性com.mongodb.Mongo如果WriteConcern没有设置MongoTemplate的属性,它将默认为在MongoDB驱动程序的数据库或集合设置中设置属性。

WriteConcernResolver

对于更高级的情况,您希望WriteConcern在每个操作的基础上设置不同的 值(用于删除,更新,插入和保存操作),WriteConcernResolver可以配置一个名为的策略接口MongoTemplate由于 MongoTemplate用于保持POJO,因此 WriteConcernResolver可以创建一个可以将特定POJO类映射到 WriteConcern值的策略。的 WriteConcernResolver接口如下所示。

公共 接口 WriteConcernResolver {
  WriteConcern解决(MongoAction行动);
}

传入的参数MongoAction用于确定WriteConcern要使用的值,或者将模板本身的值用作默认值。 MongoAction包含正在写入的集合名称,java.lang.ClassPOJO的转换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();
  }
}

4.6保存,更新和删除文档

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 + “]” ;
  }
  
}

您可以保存,更新和删除对象,如下所示。

[注意] 注意

MongoOperationsMongoTemplate实现的接口

 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]

使用存储在数据库中的MongoConverterStringObjectIdas 之间 存在隐式转换 ,并识别属性“Id”名称的约定。

[注意] 注意

这个例子是为了显示在MongoTemplate上使用save,update和remove操作,而不是显示复杂的映射功能

本示例中使用的查询语法在“ 查询文档 ”一节中有更详细的说明

4.6.1如何在映射层处理'_id'字段

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使用Spring Converter<BigInteger, ObjectId>

如果在Java类中没有上面指定的字段或属性,那么驱动程序将生成一个隐含的“_id”文件,但不会映射到Java类的属性或字段。

当查询和更新MongoTemplate 将使用转换器来处理转换的 Query,并Update对应于上述规则保存文档,以便在查询的字段名称和类型将能够匹配什么是在你的领域类的对象。

4.6.2类型映射

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

例4.10。为一个实体定义一个TypeAlias

@TypeAlias(“pers”)
 class Person {

}

请注意,生成的文档将包含 字段中"pers"的值_class


配置自定义类型映射

下面的例子演示了如何配置自定义 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” />

4.6.3保存和插入文件的方法

有几个方便的方法 MongoTemplate来保存和插入你的对象。为了对转换过程有更精细的控制,你可以使用MappingMongoConverter例如 Converter<Person, DBObject>and 来注册Spring转换器 Converter<DBObject, Person>

[注意] 注意

插入和保存操作之间的区别在于,如果对象不存在,则保存操作将执行插入操作。

使用保存操作的简单情况是保存一个POJO。在这种情况下,集合名称将由班级名称(未完全满足)确定。您也可以使用特定的集合名称来调用保存操作。可以使用映射元数据覆盖存储对象的集合。

插入或保存时,如果未设置Id属性,则假定其值将由数据库自动生成。因此,对于自动生成的的ObjectId的成功在您的类ID属性/字段的类型必须是StringObjectId或 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接口中支持该功能的方法

  • 插入 插入一个对象。如果存在具有相同ID的现有文档,则会生成错误。

  • insertAll以一个 Collection 对象作为第一个参数。此方法检查每个对象,并根据上面指定的规则将其插入到适当的集合中。

  • 保存保存对象覆盖可能存在的任何对象具有相同的ID。

批量插入几个对象

MongoDB驱动程序支持在一个操作中插入一组文档。下面列出了MongoOperations接口中支持该功能的方法

  • 插入 methods that take a Collection as the first argument.这将插入一个批处理写入数据库的对象列表。

4.6.4更新集合中的文档

对于更新,我们可以选择更新使用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提供流畅的样式。

执行文件更新的方法
  • updateFirst使用提供的更新文档更新与查询文档条件相匹配的第一个文档。

  • updateMulti使用提供的更新文档更新与查询文档条件相匹配的所有对象。

更新类的方法

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更新修改器取消设置 更新

4.6.5在一个集合中插入文档

与执行updateFirst 操作相关,也可以执行一个upsert操作,如果找不到与查询匹配的文档,将执行插入操作。插入的文档是查询文档和更新文档的组合。这是一个例子

(“”)是(1111)和(“firstName”)是(“Joe”)和(“Fraizer”)是(“Update”)),update(“地址“,addr),Person.class);

4.6.6在集合中查找和插入文档

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

4.6.7删除文件的方法

您可以使用几个重载的方法从数据库中删除一个对象。

  • 删除根据以下之一删除给定的文档:特定的对象实例,查询文档标准结合一个类或查询文档条件结合特定的集合名称。

4.7查询文件

你可以表达使用您的疑问Query 和Criteria它具有反映本地的MongoDB运营商的名称,如方法名称类lt, lteis,等。在 QueryCriteria类遵循流畅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一节中将对此进行更详细的介绍

4.7.1查询集合中的文档

在前面的部分中,我们看到了如何使用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类的方法

  • Criteria 全部 (Object o)使用$all操作员创建一个标准

  • Criteria 并将 指定 (String key) 的链接添加 到当前 并返回新创建的链接CriteriakeyCriteria

  • 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班有用于提供查询选项的一些其他方法。

Query类的方法

  • Query addCriteria (Criteria criteria)用于向查询添加附加条件

  • Field 字段 ()用来定义字段被包括在查询结果中

  • Query 限制 (int limit)用于限制返回结果的大小到提供的限制(用于分页)

  • Query 跳过 (int skip)用于跳过结果中提供的文档数目(用于分页)

  • Sort 排序 ()用于为结果提供定义排序

4.7.2查询文件的方法

查询方法需要指定将被返回的目标类型T,并且对于应该对返回类型所指示的集合以外的集合进行操作的查询,它们也被重载并具有显式集合名称。

  • findAll Query从集合中获取T类型对象的列表。

  • findOne将集合上的即席查询的结果映射到指定类型的对象的单个实例。

  • findById返回给定的id和目标类的对象。

  • 查找将集合上的即席查询的结果映射到指定类型的列表。

  • findAndRemove将集合上的即席查询的结果映射到指定类型的对象的单个实例。与查询匹配的第一个文档将返回并从数据库中的集合中删除。

4.7.3地理空间查询

MongoDB的支持通过使用等运营商的地理空间查询$near$within和 $nearSphereCriteria该类可以使用特定于地理空间查询的方法也有一些形状类,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.9917140.7388680.01);
列表<Venue> venues = 
    template.find(查询(Criteria.where( 所在地”).withinCenter(圆圈)),地点。);

Circle使用球形坐标查找场地,可以使用以下查询

圈圈= 圈( - 73.9917140.7388680.003712240453784);
列表<Venue> venues = 
    template.find(查询(Criteria.where( 所在地”).withinCenterSphere(圆圈)),地点。);

Box在下面的查询中可以使用查找场地

//左下然后右上 
箱盒= 盒(点( - 73.9975640.73083),点( - 73.98813540.741404));  
列表<Venue> venues = 
    template.find(查询(Criteria.where( 所在地”).withinBox(盒)),地点。);

要找到附近的场地Point,可以使用以下查询

点点= 点( - 73.9917140.738868);
列表<Venue> venues = 
    template.find(查询(Criteria.where( 所在地”).near(点).maxDistance(0.01)),地点。);

要找到Point使用球形坐标附近的场地,可以使用以下查询

点点= 点( - 73.9917140.738868);
列表<Venue> venues = 
    template.find(new Query(
        Criteria.where(“location”).nearSphere(point).maxDistance(0.003712240453784)),
        地点。);
查询附近的地理位置

MongoDB支持查询数据库中的地理位置,并同时计算与给定源的距离。使用地理附近查询,可以表达如下查询:“查找周围10英里内的所有餐馆”。这样做MongoOperations提供了 geoNear(…)方法 NearQuery作为参数以及已经熟悉的实体类型和集合

点位置= 点( - 73.9917140.738868);
NearQuery query = NearQuery.near(location).maxDistance(new Distance(10,Metrics.MILES));

GeoResults <餐厅> = operations.geoNear(查询,餐厅。);

正如您所看到的,我们使用NearQuery 构建器API来设置一个查询,以返回Restaurant给定范围内Point所有 实例 最多10英里。Metrics这里使用的 枚举实际上实现了一个接口,以便其他度量也可以插入到一个距离。Metric由乘法器支持将给定度量的距离值转换为本地距离。这里显示的示例将认为10英里。使用预先建好的指标之一(英里和公里)将自动触发在查询上设置球形标志。如果你想避免这种情况,只需简单地将 double值输入maxDistance(…)欲了解更多信息,请参阅的JavaDoc中NearQuery和 Distance

接近操作的地理位置返回GeoResults封装GeoResult实例的 封装器对象 包装 GeoResults允许访问所有结果的平均距离。一个GeoResult 对象只是简单地把找到的实体加上它与原点的距离。

4.8地图 - 减少操作

您可以使用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字符串传递。

4.8.1示例使用

要理解如何执行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。);

请注意,您也可以在查询中指定其他限制值和排序值,但不能跳过值。

4.9集团运营

作为替代使用的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字符串传递。

4.9.1使用示例

为了理解群体操作是如何工作的,使用了下面的例子,这是有些人为的。更实际的例子请参考“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);

4.10聚合框架支持

Spring Data MongoDB支持在2.2版本中引入MongoDB的Aggregation Framework。

MongoDB文档描述的聚合框架如下:“ MongoDB聚合框架提供了一种计算聚合值而不必使用map-reduce的方法。虽然map-reduce功能强大,但对于许多简单的聚合任务来说,通常比完成或平均字段值更困难。

有关更多信息,请参阅MongoDB的聚合框架和其他数据聚合工具的完整参考文档

4.10.1基本概念

在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将从此类派生输入集合的名称。否则,如果您不指定输入类,则必须明确提供输入集合的名称。如果提供输入类和输入集合,则后者优先。

4.10.2支持的聚合操作

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映射或添加。

4.10.3投影表达式

投影表达式用于定义作为特定聚合步骤结果的字段。投影表达式可以通过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参考文档相应部分找到

在投影表达式中支持Spring表达式

从版本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

4.10.4聚合框架示例

以下示例演示了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操作将得到的标签列表按其出现次数降序排列 

  • 最后,我们调用aggregateMongoTemplate上的Method来让MongoDB以创建Aggregation的参数执行acutal聚合操作 

请注意,输入集合被显式指定为 Method 的 "tags"参数aggregate如果未明确指定输入集合的名称,则它是从作为newAggreationMethod的第一个参数传入的输入类派生的 

例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出现,我们通过以前的操作排除id and(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”). mod2).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表达式导出的复杂算术运算。

注意:传递给addExpressionMethod 的附加参数 可以通过索引器表达式根据它们的位置来引用。在这个例子中,我们引用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表达式中引用文档的其他字段。

4.11用自定义转换器覆盖默认映射

为了有更多的细粒度控制映射过程,您可以用注册春季转换器 MongoConverter实现如 MappingMongoConverter

MappingMongoConverter在尝试映射对象本身之前检查是否有任何可以处理特定类的Spring转换器。为了“劫持”正常的映射策略MappingMongoConverter,也许为了提高性能或其他自定义映射需求,首先需要创建Spring Converter接口的实现, 然后使用MappingConverter进行注册。

[注意] 注意

有关Spring的类型转换服务的详细信息,请参阅参考文档在这里

4.11.1使用已注册的弹簧转换器进行保存

下面显示了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;
  }
}

4.11.2使用Spring转换器读取

下面显示了一个从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;
  }
}

4.11.3使用MongoConverter注册Spring转换器

Mongo Spring命名空间提供了一种方便的方式来注册Spring的ConverterMappingMongoConverter下面的配置代码展示了如何手动注册转换器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>

4.11.4转换器消歧

一般来说,我们检查Converter 它们转换来源和目标类型实现。取决于其中的一个是否是MongoDB可以本地处理的类型,我们将把转换器实例注册为读取或写入。看看下面的例子:

//写转换器只有目标类型是Mongo可以本地处理的
 MyConverter implements Converter <Person,String> {...}

//读取转换器只有源类型是Mongo可以本地处理的
 MyConverter implements Converter <String,Person> {...}

如果你写Converter的源和目标类型是本地Mongo类型,我们无法确定是否应该把它看成是读写转换器。将转换器实例注册为两者可能会导致不需要的结果。例如,a Converter<String, Long>是不明确的,尽管在写作时尝试将所有Strings转换成 Long是没有意义的通常能够强制基础设施注册一种方式的转换器,只有我们提供 @ReadingConverter以及 @WritingConverter在转换器实施中使用。

4.12索引和集合管理

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

4.12.1创建索引的方法

我们可以在集合上创建一个索引来提高查询性能。

例4.25。使用MongoTemplate创建一个索引

mongoTemplate.indexOps(人。).ensureIndex(指数()上(“名”,Order.ASCENDING));        

  • ensureIndex确保为集合提供了所提供的IndexDefinition的索引。

您可以使用类创建标准索引和地理空间索引IndexDefinition和 GeoSpatialIndex尊敬。例如,给定上一节中定义的Venue类,您将声明如下所示的地理空间查询

mongoTemplate.indexOps(场馆).ensureIndex( GeospatialIndex( 位置”));

4.12.2访问索引信息

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

4.12.3使用集合的方法

现在是时候看一些代码示例,展示如何使用 MongoTemplate首先我们看看创建我们的第一个集合。

例4.26。使用MongoTemplate处理集合

DBCollection集合= null;
if(!mongoTemplate.getCollectionNames()。contains(“MyNewCollection”)){
    collection = mongoTemplate.createCollection(“MyNewCollection”);
}

mongoTemplate.dropCollection(“MyNewCollection”);        

  • getCollectionNames返回一组集合名称。

  • collectionExists检查是否存在具有给定名称的集合。

  • createCollection创建一个不封闭的集合

  • dropCollection删除集合

  • getCollection按名称获取集合,如果不存在则创建集合。

4.13执行命令

您也可以DB.command( )使用上的executeCommand(…) 方法获取MongoDB驱动程序的方法MongoTemplate这些也将执行到Spring的DataAccessException层次结构的异常转换 

4.13.1执行命令的方法

  • CommandResult executeCommand (DBObject command) 执行一个MongoDB命令。

  • CommandResult executeCommand (String jsonCommand) 执行一个表示为JSON字符串的MongoDB命令。

4.14生命周期事件

内置到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方法。

4.15例外翻译

Spring框架为各种数据库和映射技术提供了异常转换。传统上,这是针对JDBC和JPA的。对MongoDB的Spring支持通过提供org.springframework.dao.support.PersistenceExceptionTranslator 接口的实现将这个特性扩展到MongoDB数据库 

映射到Spring的一致性数据访问异常层次结构的动机是您可以编写可移植和描述性的异常处理代码,而无需依靠MongoDB错误代码进行编码所有Spring的数据访问异常都是从根DataAccessException继承的,所以你可以确定你将能够在一个try-catch块中捕获所有与数据库相关的异常。请注意,MongoDB驱动程序抛出的所有异常并不是从MongoException类继承的。内部异常和消息被保留,所以没有信息丢失。

一些由MongoExceptionTranslatorcom.mongodb.Network 执行的映射 为DataAccessResourceFailureException,MongoException错误代码为1003,12001,12010,12011,12012 InvalidDataAccessApiUsageException查看实现以获取更多关于映射的细节。

4.16执行回调

所有Spring模板类的一个常见设计特征是所有的功能都被路由到一个模板执行回调方法。这有助于确保可能需要的异常和任何资源管理的一致性。虽然JDBC和JMS比MongoDB更需要它,但它仍然为异常转换和日志记录提供了一个单独的位置。因此,使用xe执行回调是访问MongoDB驱动程序DBDBCollection对象来执行非公开操作的首选方法,这些操作并不作为方法公开 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;
  }
});

4.17 GridFS支持

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中检索文件时不支持定义排序标准。因此,在Query实例中 定义的任何排序标准 find(…)都将被忽略。

从GridF读取文件的另一个选择是使用ResourcePatternResolver 接口引入的方法它们允许将Ant路径传递到方法ar中,从而检索与给定模式匹配的文件。

例4.33。使用GridFsTemplate来读取文件

class GridFsClient {

  @Autowired
  GridFsOperations操作;

  @Test
   public  void readFilesFromGridFs {
    GridFsResources [] txtFiles = operations.getResources(“* .txt”);
  }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值