Docs 菜单
Docs 主页
/ /
Atlas App Services

Atlas Functions

在此页面上

  • Overview
  • 如何编写函数
  • 用户和系统函数
  • 定义函数
  • 调用函数
  • 约束

Atlas Function 是一段服务器端 JavaScript 代码,您编写该代码来定义应用的行为。您可以直接从客户端应用调用应用的函数,也可以定义自动集成和调用函数的服务。

函数可以调用其他函数,并包含内置客户端,用于处理 MongoDB Atlas 集群中的数据。这些函数还包括有用的全局实用程序,支持常见的 Node.js 内置模块,并且可以从 npm 注册表中导入和使用外部包。

返回问候语的基本函数
exports = function(name) {
return `Hello, ${name ?? "stranger"}!`
}

调用函数时,应用程序会将请求路由到托管应用程序服务器,该服务器为代码求值并返回结果。此模型使函数具备无服务器性质,也即您不必部署和管理服务器来运行代码。您只需编写函数源代码,然后应用程序处理执行环境。

函数会在反映其执行环境的上下文中运行。该上下文包括调用该函数的用户、如何进行调用以及调用该函数时应用的状态。您可以使用上下文来运行特定于用户的代码,并与应用的其他部分配合使用。

要了解有关如何使用函数上下文的详情,请参阅上下文。

函数可以运行您定义的任意 JavaScript 代码,这意味着您几乎可以在任何情况下使用这些函数。常见使用案例包括低延迟、短时间运行的任务,如数据移动、转换和验证。您还可以使用它们连接外部服务,从客户端应用程序中抽象出实施细节。

除了直接调用的函数之外,您还可以为各种服务写入函数,例如HTTPS endpoints 、触发器和GraphQL自定义解析程序( GraphQL已弃用,学习;了解更多)。 这些服务会自动调用函数来处理特定事件。 示例,每当数据库trigger观察到变更事件时,它就会将该变更事件作为参数来调用关联的函数。 然后,您可以在trigger函数中访问权限变更事件的信息并做出适当响应。

提示

另请参阅:

函数的代码本质上是一个已命名的JavaScript源文件,这意味着您可以在单个函数文件中定义多个JavaScript函数。 该文件必须导出单个JavaScript函数以提供服务传入调用的入口点。 按名称调用函数时,实际上是在调用函数源文件中分配给 exports的JavaScript函数。

例如,以下简易函数可接受 name 参数、添加日志消息,并为所提供的姓名返回一句问候语:

exports = function Hello(name) {
console.log(`Said hello to ${name}`);
return `Hello, ${name}!`;
};

您可以使用现代 JavaScript 语法和导入包来定义更多复杂函数:

// You can use ES6 arrow functions
const uppercase = (str) => {
return str.toUpperCase();
};
// You can use async functions and await Promises
exports = async function GetWeather() {
// You can get information about the user called the function
const city = context.user.custom_data.city;
// You can import Node.js built-ins and npm packages
const { URL } = require("url");
const weatherUrl = new URL("https://example.com");
weatherUrl.pathname = "/weather";
weatherUrl.search = `?location="${city}"`;
// You can send HTTPS requests to external services
const weatherResponse = await context.http.get({
url: url.toString(),
headers: {
Accept: ["application/json"],
},
});
const { current, forecasts } = JSON.parse(weatherResponse.body.text());
return [
`Right now ${uppercase(city)} is ${current.temperature}°F and ${current.weather}.`,
`Here's the forecast for the next 7 days:`,
forecasts
.map((f) => `${f.day}: ${f.temperature}°F and ${f.weather}`)
.join("\n "),
].join("\n");
};
Right now NEW YORK CITY is 72°F and sunny.
Here's the forecast for the next 7 days:
Tuesday: 71°F and sunny
Wednesday: 72°F and sunny
Thursday: 73°F and partly cloudy
Friday: 71°F and rainy
Saturday: 77°F and sunny
Sunday: 76°F and sunny
Monday: 74°F and sunny

函数会自动将返回的值序列化为扩展JSON 。 这对于保留类型信息很有用,但可能不是应用程序所期望的。

例如,从以下函数返回的对象中的值将转换为结构化 EJSON 值:

exports = function() {
return {
pi: 3.14159,
today: new Date(),
}
}
{
"pi": {
"$numberDouble": "3.14159"
},
"today": {
"$date": {
"$numberLong": "1652297239913"
}
}
}

要返回标准 JSON 形式的值,请对该值调用 JSON.stringify(),然后返回字符串化后的结果:

exports = function() {
return JSON.stringify({
pi: 3.14159,
today: new Date(),
})
}
"{\"pi\":3.14159,\"today\":\"2022-05-11T19:27:32.207Z\"}"

函数可以在两个上下文中运行,具体取决于它们的配置和调用方式:

  • 用户函数在应用程序的特定用户的上下文中运行。通常这是调用该函数的登录用户。用户函数受规则模式验证的约束。

  • 系统功能系统用户而非特定应用程序用户的身份运行。系统函数可以完全访问 MongoDB CRUD 和 Aggregation API,并绕过所有规则和模式验证。

注意

动态 context.user 参考

context.user 的引用始终解析为调用函数的经过身份验证的用户(如果有),即使该函数作为系统函数运行亦是如此。要确定某个函数是否作为系统函数运行,请调用 context.runningAsSystem()

如果函数没有经过身份验证的用户调用即执行(例如在Trigger 或 Webhook 中),则动态引用将解析为没有 id 或其他关联数据的系统用户

您可以从 App Services 用户界面或通过使用 App Services CLI 或 GitHub 部署导入函数配置和源代码来创建和管理应用程序中的函数。

1

要从 App Services 用户界面定义新的服务器端函数,请执行以下操作:

  1. 单击左侧导航菜单中的 Functions(应用用户)。

  2. 单击 Functions 页面右上角的 New Function

2

Name 字段中输入函数的唯一标识名称。此名称必须不同于应用程序中的所有其他函数。

提示

您可以在嵌套文件夹内定义函数。函数名称是以斜线分隔的路径,因此名为 utils/add 的函数将映射到应用配置文件中的 functions/utils/add.js

3

App Services 中的函数始终在特定应用程序用户的上下文中执行,或作为绕过规则的系统用户执行。要配置函数的执行用户,请指定 App Services 应使用的身份验证类型。

身份验证类型
说明
应用程序身份验证
这种类型的身份验证将函数配置为在客户端应用程序调用该函数时登录的现有应用程序用户的上下文中运行。如果已从另一个函数调用该函数,那么它将继承执行该函数的用户。
记录
这种类型的身份验证将函数配置为以系统用户身份运行,该用户对 MongoDB CRUD 和 Aggregation API 具有完全访问权限,并且不受任何规则、角色或权限的影响。
用户 ID
这种类型的身份验证将函数配置为始终作为特定应用程序用户运行。
脚本
这种类型的身份验证将函数配置为作为特定应用程序用户运行,该用户根据您定义的自定义函数的结果确定。该函数必须返回特定用户的 id 字符串,或者可以通过返回 { "runAsSystem": true } 来指定系统用户。
用户界面中输入的身份验证配置
点击放大
4

默认情况下,App Services 在每次执行函数的日志条目中包含函数收到的参数。如果要阻止 App Services 记录参数,请禁用 Log Function Arguments

5

通过定义 Can Evaluate 表达式,可以根据每个请求的内容动态授权请求。每次调用函数时,App Services 都会对表达式进行评估。如果未指定表达式,则 App Services 会自动授权所有经过身份验证的传入请求。

表达式可以扩展标准表达式变量,包括 %%request%%user 扩展。

函数的“可以评估”用户界面中输入的JSON表达式
点击放大
6

默认情况下,您可以从客户端应用程序调用函数,也可以调用同一应用程序中的其他函数。您可以通过将 Private 设置为 true 来阻止客户端应用程序查看或调用函数。

您仍然可以从表达式和其他函数(包括传入的 webhook 和触发器)中调用私有函数。

用户界面中的私有函数切换
点击放大
7

创建并配置新函数后,就可以编写调用该函数时运行的 JavaScript 代码。您可以使用函数编辑器直接在 App Services 用户界面中编写代码。

注意

您可以在函数中使用大多数现代 (ES6+) JavaScript 功能,包括异步/等待、解构和模板文本。

从函数的 Settings 页面:

  1. 单击 Function Editor 标签页。

  2. 将 javascript 代码添加到函数。该代码至少必须为 exports 分配一个函数,如下例所示:

    exports = function() {
    return "Hello, world!";
    };
8

编写完函数代码后,单击 Function EditorSettings 标签页中的 Save

保存函数后,您可以立即开始使用。

1
appservices pull --remote=<App ID>
2

Atlas Function运行标准 ES 6 + 您从单个文件导出的JavaScript函数。 在functions目录或其子目录之一中创建与函数同名的.js文件。

touch functions/myFunction.js

提示

您可以在functions目录中的嵌套文件夹内定义函数。 在函数名称中使用斜杠来指示其目录路径。

创建函数的.js文件后,写入函数源代码,例如:

exports = async function hello(...args) {
// Write your function logic here! You can...
// Import dependencies
const assert = require("assert")
assert(typeof args[0] === "string")
// Use ES6+ syntax
const sayHello = (name = "world") => {
console.log(`Hello, ${name}.`)
}
// Return values back to clients or other functions
return sayHello(args[0])
}

注意

您可以在函数中使用大多数现代 (ES 6 +) JavaScript功能,包括异步/等待、解构和模板字面量。 要查看App Services是否支持特定功能,请参阅JavaScript支持。

3

在应用程序的functions目录中,打开config.json文件并将新函数的配置对象添加到大量中。 该对象必须具有以下形式:

{
"name": "<Function Name>",
"private": <Boolean>,
"can_evaluate": { <JSON Expression> },
"disable_arg_logs": <Boolean>,
"run_as_system": <Boolean>,
"run_as_user_id": "<App Services User ID>",
"run_as_user_id_script_source": "<Function Source Code>"
}
1

App Services中的函数始终在特定应用程序用户的上下文中或作为系统用户(绕过规则)执行。 要配置函数的执行用户,请指定App Services应使用的身份验证类型:

  • 记录

    要以系统用户身份执行函数,请使用以下配置:

    {
    "run_as_system": true,
    "run_as_user_id": "",
    "run_as_user_id_script_source": ""
    }
  • user

    要以特定用户身份执行函数,请使用以下配置:

    {
    "run_as_system": false,
    "run_as_user_id": "<App Services User Id>",
    "run_as_user_id_script_source": ""
    }
  • 脚本

    执行函数的第三种方法是指定另一个返回用户 ID 的函数。 您的函数将以该用户身份执行。 为此,请使用以下配置:

    {
    "run_as_system": false,
    "run_as_user_id": "",
    "run_as_user_id_script_source": "<Function Source Code>"
    }
2

要在其日志条目中包含函数作为参数接收的任何值,请将disable_arg_logs设立为false

3

通过定义 Can Evaluate 表达式,可以根据每个请求的内容动态授权请求。每次调用函数时,App Services 都会对表达式进行评估。如果未指定表达式,则 App Services 会自动授权所有经过身份验证的传入请求。

表达式可以扩展标准表达式变量,包括 %%request%%user 扩展。

例子

仅当发件人的IP解决未包含在指定的地址列表中时,以下表达式才会授权传入请求。

{
"%%request.remoteIPAddress": {
"$nin": [
"248.88.57.58",
"19.241.23.116",
"147.64.232.1"
]
}
}
4

默认情况下,您可以从客户端应用程序调用函数,也可以调用同一应用程序中的其他函数。您可以通过将 private 设置为 true 来阻止客户端应用程序查看或调用函数。

您可以从规则表达式或其他函数中调用私有函数,包括HTTPS endpoints和触发器。

4

推送函数配置和源代码以将其部署到您的应用。 推送该函数后,您可以立即开始使用。

appservices push

您可以通过其他函数、连接的客户端应用程序或 App Services CLI 调用某个函数。

本部分中的示例演示了如何调用名为 sum 的简易函数,该函数可接受两个参数、添加这两个参数并返回结果:

// sum: adds two numbers
exports = function sum(a, b) {
return a + b;
};

可以通过 context.functions 接口从一个函数调用另一个函数,该接口可可任何函数中用作全局变量。这包括 HTTPS 端点、触发器和 GraphQL 自定义解析器(已弃用,了解详情)。被调用函数与调用函数在相同的上下文中运行。

// difference: subtracts b from a using the sum function
exports = function difference(a, b) {
return context.functions.execute("sum", a, -1 * b);
};

可以通过 App Services CLI 使用 function run 命令调用函数。该命令以 EJSON 形式返回函数结果以及任何日志或错误消息。

appservices function run \
--name=sum \
--args=1 --args=2

默认情况下,函数在系统上下文中运行。要在特定用户的上下文中调用函数,请将其用户 ID 纳入 --user 参数。

appservices function run \
--name=sum \
--args=1 --args=2 \
--user=61a50d82532cbd0de95c7c89

可以使用 %function 操作符从规则表达式调用函数。该操作符可计算出函数的返回值。如果函数抛出错误,则表达式的计算结果为 false

{
"numGamesPlayed": {
"%function": {
"name": "sum",
"arguments": [
"%%root.numWins",
"%%root.numLosses"
]
}
}
}

重要

使用函数时,确保对客户端数据进行清理,以防止代码注入。

您可以从使用 Realm SDK 连接的客户端应用程序或通过传输协议来调用函数。有关演示如何从客户端应用程序调用函数的代码示例,请参阅 Realm SDK 的文档:

后退

已弃用的功能