在mongodb服务器上存储和执行 js 函数 - 存储过程

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介: 虽然官方不推荐使用将业务逻辑存储在数据库中,并且提示在 mongodb 中执行 javascript 存在性能限制。但实际上,将 javascript 函数存储在 mongodb 中执行,还是非常有必要的,更方便,许多场景下性能会更好(在执行大量查询处理时不需要将数据传回客户端引擎)。在目前的版本中,我们任然可以将 javascript 函数存储在 mongodb 内置的一个特殊集合 db.system.js 中,然后这些变量就可以在任何 mongodb 的 javascript 上下文中调用,包括:db.eval()、$where子句、mapReduce。自从 mongodb 3

虽然官方不推荐使用将业务逻辑存储在数据库中,并且提示在 mongodb 中执行 javascript 存在性能限制。

但实际上,将 javascript 函数存储在 mongodb 中执行,还是非常有必要的,更方便,许多场景下性能会更好(在执行大量查询处理时不需要将数据传回客户端引擎)。

在目前的版本中,我们任然可以将 javascript 函数存储在 mongodb 内置的一个特殊集合 db.system.js 中,然后这些变量就可以在任何 mongodb 的 javascript 上下文中调用,包括:db.eval()、$where子句、mapReduce。

自从 mongodb 3.0 版本及之后,执行 db.eval() 会得到一个 Warning: db.eval is deprecated,意味着该 api 在未来即将被删除。但目前社区还没有提供类似的替代方案,并且该 api 在最新的 mongodb 4.0 版本中任然可以正常使用。

相关讨论可以参考: SERVER-17453 warn that db.eval() / eval command is deprecated - MongoDB

如何使用
首先登陆 mongo shell

$ mongo

use testdb
新增一个函数
db.system.js.save({
_id: 'doSomeThing', // 存储过程名称
value(args) { // 过程体
return db.courses.count();

},
description: 'just a test.', // 描述,非必须
});
或者

db.system.js.insert({
_id: 'doSomeThing', // 存储过程名称
value(args) { // 过程体

return db.courses.count();

},
description: 'just a test.', // 描述,非必须
});
修改已经存在的函数
db.system.js.update(
{

_id: 'doSomeThing', // 存储过程名称

},
{

value() { // 过程体
  return db.courses.count();
},

}
);
注意,新增时的参数是一个 object,而修改(update)时的参数类似 db.collect.update(, ),两个参数均为 object。
执行
// 使用 eval 命令
db.runCommand({

eval:"doSomeThing(args)",
args: null,
nolock: true

});

// 或者使用 helper 方法 db.eval
db.eval("doSomeThing(args)");
// 也可以立即执行一个函数
db.eval(function(arg1,arg2){}, arg1, arg2);
查看已经存储的 javascript 函数
db.system.js.find();
注意事项
写锁定
需要注意的是,执行 db.eval() 时,mongodb 采用了全局写锁定,因此,执行 db.eval() 时将阻止对数据库的所有其他读写操作,意味着将阻塞其他任务,直到 db.eval() 执行结束,这在执行长时间任务时有些麻烦。

使用 eval 命令也同样存在全局写锁定,但可以设置 nolock 选项避免。db.eval() 和 eval 命令的不同之处只是不支持 nolock 选项。

javascript 解释器
一般来说,我们使用 mongo 命令登陆 shell,此时使用的是 mongoshell 的 javascript 解释器,不同版本的 shell 所支持的语法并不同。 而论坛使用 eval 命令或者 db.eval() 时,所使用的 javascript 解释器为服务器的解释器,这和 mongoshell 有所区别。

此外,在 mongodb 3.2 中,mongoshell 和服务器端的 javascript 引擎由 V8 更改为 SpiderMonkey 。你可以在 shell 中执行 db.serverBuildInfo() ,查看结果中的 javascriptEngine 字段确认当前使用的 javascript 引擎。

SpiderMonkey 增加了对 ES6 的支持,包括箭头函数、解构等。但仅此而已,实测 mongodb 4.0 版本中仍然不支持这样的语法: const obj={...obj1}; 。

所以,在编写 javascript 函数时,需要注意 mongodb 的版本差异和内置的 javascript 引擎类型,避免语法错误。

访问限制
自 mongodb 2.6 版本之后,如果启用了密码登陆,则必须有权访问所有资源上的所有操作才能运行 eval。

注:这样会导致安全风险。
如果你确定要这么做,可以创建一个拥有 anyAction 和 anyResource 的角色,并添加一个对应的用户。

use admin
db.createRole({
role: 'sysadmin',
roles: [],
privileges: [

{
  resource: { anyResource: true },
  actions: [ 'anyAction' ],
},

],
});

use dbtest
db.createUser({
user: 'root',
pwd: 'root',
roles: [

{ role: 'sysadmin', db: 'admin' },

],
});
最后
除了以上介绍的方法以外,mongodb 还支持其他直接执行 javascript 的方案,例如 mongoshell 中所支持的 load() 方法可以直接加载一个 js 文件并执行。

鉴于篇幅所限,更多介绍可以参考官方文档:Server-side JavaScript — MongoDB Manual

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
15天前
|
JavaScript
变量和函数提升(js的问题)
变量和函数提升(js的问题)
|
15天前
|
JavaScript
常见函数的4种类型(js的问题)
常见函数的4种类型(js的问题)
10 0
|
15天前
|
JavaScript
写一个函数将N组<>(包含开始和结束),进行组合,并输出组合结果 (js)
写一个函数将N组<>(包含开始和结束),进行组合,并输出组合结果 (js)
9 0
|
26天前
|
自然语言处理 JavaScript 网络架构
js开发:请解释什么是ES6的箭头函数,以及它与传统函数的区别。
ES6的箭头函数以`=>`定义,简化了函数写法,具有简洁语法和词法作用域的`this`。它无`arguments`对象,不能用作构造函数,不支持`Generator`,且不改变`this`、`super`、`new.target`绑定。适用于简短表达式,常用于异步编程和高阶函数。
17 5
|
1月前
|
JavaScript 前端开发 网络架构
JavaScript 谈谈对箭头函数的理解及其与普通函数的区别。
JavaScript 谈谈对箭头函数的理解及其与普通函数的区别。
17 1
|
1月前
|
前端开发 JavaScript 数据处理
在JavaScript中,什么是异步函数执行的例子
在JavaScript中,什么是异步函数执行的例子
10 0
|
1月前
|
JavaScript
JS封装节流函数
JS封装节流函数
15 0
|
1月前
|
JavaScript 前端开发
javascript箭头函数
javascript箭头函数
|
1月前
|
JavaScript 小程序
微信小程序 wxml 中使用 js函数
微信小程序 wxml 中使用 js函数
67 0
|
28天前
|
存储 机器学习/深度学习 弹性计算
ecs实例规格存储和I/O需求
阿里云ECS提供多种实例类型满足不同需求:通用型适合中小型应用;计算型强调CPU性能,适合大数据分析;存储型针对高I/O场景,如数据库;内存型适合内存敏感应用;GPU型用于GPU加速任务;异构计算型包含FPGA、ASIC。实例搭配不同性能的云盘(如ESSD)以调整IOPS和吞吐量。选择实例时,需综合考虑应用对计算、内存和存储I/O的需求。
15 1