本文将介绍怎样使用 Spring Data MongoDB 提供的 ScriptOperations,在 MongoDB 上执行 JavaScript 脚本。
MongoDB 允许通过直接发送脚本或调用存储的脚本在服务器上运行 JavaScript 函数。
MongoDB 4.2 移除了被 ScriptOperations 使用的 eval 命令的支持,并且没有提供其他替代方案。因此,ScriptOperations 不在推荐使用,该接口的声明如下:
package org.springframework.data.mongodb.core;
import java.util.Set;
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
import org.springframework.lang.Nullable;
/**
* Script operations on {@link com.mongodb.client.MongoDatabase} level. Allows interaction with server side JavaScript functions.
*
* @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7
* @deprecated since 2.2. The {@code eval} command has been removed without replacement in MongoDB Server 4.2.0.
*/
@Deprecated
public interface ScriptOperations {
   //...
}官方已经不推荐使用了,但还是有必要看看它是干什么的。
ScriptOperations 可以通过 MongoTemplate 的 scriptOps() 方法获取,ScriptOperations 并为 JavaScript 的使用提供基本的抽象。scriptOps() 方法定义如下:
ScriptOperations scriptOps() 返回可以在 MongoDatabase 级别上执行的 ScriptOperations 对象。
ScriptOperations 接口定义的主要方法如下:
Object all(String scriptName, Object... args) 用它的名字调用 JavaScript。
Object execute(ExecutableMongoScript script, Object... args) 执行脚本,通过它的名字调用它或直接发送它。
boolean exists(String scriptName) 检查 MongoDatabase 中是否存在给定名称的服务器端 JavaScript。
Set<String> getScriptNames() 返回可以调用的 JavaScript 函数的名称。
NamedMongoScript register(ExecutableMongoScript script) 存储给定的 ExecutableMongoScript 对象,生成一个名称,以便随后可以通过名称来调用。
NamedMongoScript register(NamedMongoScript script) 在数据库中注册给定的名称 MongoScript。
(1)直接运行 JavaScript 脚本,使用 ExecutableMongoScript 定义一个可执行的 JavaScript 脚本,代码如下:
ScriptOperations scriptOps = template.scriptOps();
// 定义一个脚本
ExecutableMongoScript echoScript = new ExecutableMongoScript("function(x) { return x; }");
// 直接运行脚本
scriptOps.execute(echoScript, "directly execute script");(2)通过脚本名称运行脚本,代码如下:
ScriptOperations scriptOps = template.scriptOps();
// 定义一个脚本
ExecutableMongoScript echoScript = new ExecutableMongoScript("function(x) { return x; }");
// 使用 echo 名称注册 echoScript 脚本
scriptOps.register(new NamedMongoScript("echo", echoScript));
// 通过 echo 名称执行脚本
scriptOps.call("echo", "execute script via name");下面是通过 ScriptOperations 执行脚本的完整代码,如下:
package com.hxstrive.springdata.mongodb;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.ScriptOperations;
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
/**
* ScriptOperations 操作 JavaScript 脚本
* @author hxstrive.com
*/
@SpringBootTest
class ScriptOperationsDemo {
   @Autowired
   private MongoTemplate mongoTemplate;
   @Test
   public void directlyExecuteScript() {
       // 获取 ScriptOperations 对象
       ScriptOperations scriptOps = mongoTemplate.scriptOps();
       // 创建一个简单的脚本
       // 将接收的参数 x 前后添加固定字符,然后返回
       ExecutableMongoScript echoScript = new ExecutableMongoScript("function(x) { return '[' + x + ']'; }");
       // 执行脚本
       Object result = scriptOps.execute(echoScript, "directly execute script");
       System.out.println(result);
       // 结果:
       // [directly execute script]
       // 注意:笔者运行的 MongoDB 版本为 3.4.15,在 5.0.14 版本运行抛出如下错误:
       // com.mongodb.MongoCommandException: Command failed with error 59 (CommandNotFound):
       // 'no such command: '$eval'' on server localhost:27017.
       // The full response is {"ok": 0.0, "errmsg": "no such command: '$eval'", "code": 59,
       // "codeName": "CommandNotFound"}
   }
   @Test
   public void directlyExecuteScript2() {
       ScriptOperations scriptOps = mongoTemplate.scriptOps();
       // 定义一个脚本
       ExecutableMongoScript echoScript = new ExecutableMongoScript("function(x) { return '[' + x + ']'; }");
       // 使用 echo 名称注册 echoScript 脚本
       scriptOps.register(new NamedMongoScript("echo", echoScript));
       // 通过 echo 名称执行脚本
       Object result = scriptOps.call("echo", "execute script via name");
       System.out.println(result);
       // 结果:
       // [execute script via name]
   }
}其中,Person 实体类的代码如下:
package com.hxstrive.springdata.mongodb.entity;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
@Builder
public class Person {
   /** 用户ID */
   private int id;
   /** 用户姓名 */
   private String name;
   /** 年龄 */
   private int age;
   /** 电子邮件 */
   private String email;
}
            