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

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 虽然官方不推荐使用将业务逻辑存储在数据库中,并且提示在 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

目录
相关文章
|
11月前
|
存储 JavaScript 前端开发
JavaScript中的数据类型以及存储上的差别
通过本文的介绍,希望您能够深入理解JavaScript中的数据类型及其存储差别,并在实际编程中灵活运用这些知识,以提高代码的性能和稳定性。
218 3
|
12月前
|
NoSQL 容灾 MongoDB
MongoDB主备副本集方案:两台服务器使用非对称部署的方式实现高可用与容灾备份
在资源受限的情况下,为了实现MongoDB的高可用性,本文探讨了两种在两台服务器上部署MongoDB的方案。方案一是通过主备身份轮换,即一台服务器作为主节点,另一台同时部署备节点和仲裁节点;方案二是利用`priority`设置实现自动主备切换。两者相比,方案二自动化程度更高,适合追求快速故障恢复的场景,而方案一则提供了更多的手动控制选项。文章最后对比了这两种方案与标准三节点副本集的优缺点,指出三节点方案在高可用性和数据一致性方面表现更佳。
922 5
|
SQL NoSQL Java
springboot操作nosql的mongodb,或者是如何在mongodb官网创建服务器并进行操作
本文介绍了如何在Spring Boot中操作NoSQL数据库MongoDB,包括在MongoDB官网创建服务器、配置Spring Boot项目、创建实体类、仓库类、服务类和控制器类,以及如何进行测试。
209 1
springboot操作nosql的mongodb,或者是如何在mongodb官网创建服务器并进行操作
|
存储 中间件 API
Nest.js 实战 (六):使用 Session 在不同请求间存储信息
这篇文章介绍了在Nest.js中如何使用Session来记录客户状态。文章首先解释了Session的概念,然后详细说明了如何在Nest.js中安装和使用express-session,包括全局配置、参数说明、使用方式和常用方法。
367 0
Nest.js 实战 (六):使用 Session 在不同请求间存储信息
|
关系型数据库 MySQL 存储
|
存储 前端开发 安全
JavaScript进阶 - 浏览器存储:localStorage, sessionStorage, cookies
【7月更文挑战第2天】探索Web存储:localStorage持久化,sessionStorage会话限定,cookies则伴随HTTP请求。了解它们的特性和限制,如localStorage的5MB容量限制、跨域问题,sessionStorage的生命周期,及cookies的安全与带宽消耗。使用时需权衡安全、效率与应用场景。示例代码展示存储与检索方法。
993 2
|
存储 JavaScript 前端开发
JavaScript中的对象是数据结构,存储键值对,键为字符串,值可为任意类型,包括函数(作为方法)
【6月更文挑战第25天】JavaScript中的对象是数据结构,存储键值对,键为字符串,值可为任意类型,包括函数(作为方法)。
94 2
|
存储 JavaScript 前端开发
JavaScript中的数组是核心数据结构,用于存储和操作序列数据
【6月更文挑战第22天】JavaScript中的数组是核心数据结构,用于存储和操作序列数据。创建数组可以使用字面量`[]`或`new Array()`。访问元素通过索引,如`myArray[0]`,修改同样如此。常见方法包括:`push()`添加元素至末尾,`pop()`移除末尾元素,`shift()`移除首元素,`unshift()`添加到开头,`join()`连接为字符串,`slice()`提取子数组,`splice()`进行删除、替换,`indexOf()`查找元素位置,`sort()`排序数组。还有其他如`reverse()`、`concat()`等方法。
201 2
|
存储 SQL 数据库
MySQL设计规约问题之为什么要避免使用存储过程、触发器和函数
MySQL设计规约问题之为什么要避免使用存储过程、触发器和函数
|
存储 JavaScript 前端开发
JavaScript进阶 - 浏览器存储:localStorage, sessionStorage, cookies
【7月更文挑战第8天】Web开发中的客户端存储技术,如`localStorage`, `sessionStorage`和`cookies`,用于保存用户设置和跟踪活动。`localStorage`持久化存储,`sessionStorage`随页面会话消失。两者提供基本的增删查改操作,但有大小限制和安全风险。`cookies`适合会话管理,可设置过期时间并能跨域。使用时注意存储量、安全性和跨域策略,选择适合场景的存储方式。
544 0

热门文章

最新文章

推荐镜像

更多