如何在 Cloud Functions for Firebase 中访问多个实时数据库实例

Posted

技术标签:

【中文标题】如何在 Cloud Functions for Firebase 中访问多个实时数据库实例【英文标题】:How to access multiple Realtime Database instances in Cloud Functions for Firebase 【发布时间】:2018-05-31 09:04:11 【问题描述】:

我在 Firebase 项目中使用多个数据库。主(默认)数据库的云功能很好用,但是,我不能让它们为辅助数据库工作。例如,我想在具有管理员权限的节点上发出读取请求:

//this works
admin.database().ref(nodePath).once('value')...

这在主数据库中有效,但是,如果我想在另一个数据库上执行命令,它就不起作用:

//this doesn't work
admin.database(secondaryDatabaseUrl).ref(nodePath).once('value')...

虽然功能已部署,但在尝试执行云功能时控制台出现错误。

这是带有 https 触发器的云函数的代码:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const secureCompare = require('secure-compare');

exports.testFunction= functions.https.onRequest((req, res) => 
  const key = req.query.key;
  // Exit if the keys don't match
  if (!secureCompare(key, functions.config().cron.key)) 
    console.error('keys do not match');
    res.status(403).send('error1');
    return;
  
  //test read request
  //the line below crashes the function
  return admin.database('https://secondary_db_url.firebaseio.com').ref(`/testNode`).once('value').then(dataSnapshot=> 
    console.log('value', dataSnapshot.val());
    return;
  ).catch(er => 
    console.error('error', er);
    res.status(403).send('error2');
  );
);

以下是 Firebase 控制台中的错误日志:

TypeError: ns.ensureApp(...).database is not a function
    at FirebaseNamespace.fn (/user_code/node_modules/firebase-admin/lib/firebase-namespace.js:251:42)
    at exports.testFunction.functions.https.onRequest (/user_code/index.js:16:16)
    at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:26:41)
    at /var/tmp/worker/worker.js:671:7
    at /var/tmp/worker/worker.js:655:9
    at _combinedTickCallback (internal/process/next_tick.js:73:7)
    at process._tickDomainCallback (internal/process/next_tick.js:128:9)

如果我不指定辅助数据库 URL,该函数将在我的主数据库上发出读取请求,效果很好:

//this works
return admin.database().ref(`/testNode`).once('value').then(dataSnapshot=> 
...

我正在使用最新的 SDK 版本:"firebase-admin": "^5.5.1""firebase-functions": "^0.7.3"

那么,如何使用管理员权限在云函数中获取辅助数据库的实例?

【问题讨论】:

这真的是日志中唯一有用的东西吗?请显示演示问题的完整代码。你是否从 Promise 中发现错误? 嗨,Doug,您可以查看我更新的问题。实际上,Firebase 控制台中的错误日志在几分钟后开始出现,这就是为什么我之前没有指定它们的原因。 【参考方案1】:

所以看起来您正在尝试使用 javascript Web 客户端 API 访问多个数据库。像这样将数据库的 URL 传递给 API 不适用于 Admin SDK:

admin.database('https://secondary_db_url.firebaseio.com').ref(`/testNode`)

相反,您必须 initialize a second app,为其命名,然后将该应用程序传递给 Admin SDK API。这是一个完整的示例,它将相同的数据写入同一个项目中的两个不同的数据库实例:

const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)

const otherConfig = Object.assign(, functions.config().firebase)
otherConfig.databaseURL = 'https://your-other-db.firebaseio.com/'
const otherApp = admin.initializeApp(otherConfig, 'otherAppName')

exports.foo = functions.https.onRequest((req, res) => 
    const data =  foo: 'bar' 
    const p1 = admin.database().ref('data').set(data)
    const p2 = admin.database(otherApp).ref('data').set(data)
    Promise.all([p1, p2]).then(() => 
        res.send("OK")
    )
    .catch(error => 
        res.status(500).send(error)
    )
)

【讨论】:

谢谢,成功了! Hiranya Jayathilaka 的回答也很有效。 所以我尝试了const db2 = admin.app()database('https://secondary_db_url.firebaseio.com').ref(); 并尝试更新,它显示成功更新的日志但辅助数据库中没有任何变化?如果这不起作用,为什么没有错误? 随着实时数据库测试版的结束,这已经过时了。请参阅下面的新方法。【参考方案2】:

以下是使用 Admin SDK 通过 URL 访问数据库的方法:

let app = admin.app();
let ref = app.database('https://secondary_db_url.firebaseio.com').ref();

这是来自 Admin SDK 集成测试的示例:https://github.com/firebase/firebase-admin-node/blob/master/test/integration/database.js#L52

【讨论】:

这些多个数据库是在同一个项目上还是来自不同的 firebase 项目? 他们来自同一个项目。 如何在同一项目的 Firestore 中添加辅助数据库?有可能吗? @Ayyappa ***.com/a/48649303/12373446 Stevenson 先生的这个回答可能有助于多个 Firestore 实例的想法!很晚了,但希望它可以帮助未来的开发者[:【参考方案3】:

所以如果两个答案都不起作用。

发生在我身上的是这两种方法都没有任何错误,但数据库的第二个实例没有得到更新。

我更新了 npm 和 firebase CLI,它工作正常。

还有@Dough Stevenson 你Passing the URL of the database to the API like this **does** work with the Admin SDK

这是来自 Firebase 的一篇不错的博客,内容大致相同 Firebase Blog : Easier scaling with multi-database support!

【讨论】:

【参考方案4】:

现在使用云功能 > 1.1,这是在这个问题上挽救了我生命的文档链接。

https://firebase.google.com/docs/database/usage/sharding#connect_your_app_to_multiple_database_instances

所以,它在我的云函数 index.js 的顶部看起来像这样:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const dev = admin.initializeApp(
  databaseURL: "https://appdev.firebaseio.com"
, 'dev');

const v2 = admin.initializeApp(
  databaseURL: "https://appv2.firebaseio.com"
, 'v2');

然后,在我的克隆函数函数代码中我可以做:

//will change stuff on default database
admin.database().ref().child(`stuff/$stuffId`).set(myStuff)

//will change stuff on my dev database
admin.database(dev).ref().child(`stuff/$stuffId`).set(myStuff)

//will change stuff on my v2 database
admin.database(v2).ref().child(`stuff/$stuffId`).set(myStuff)

【讨论】:

admin.database(v2).ref().child(stuff/$stuffId).set(myStuff)【参考方案5】:

在 Firebase Functions v3.14.0 上更新此内容。这些答案都不适合我,所以我实现了this solution

instance 注册一个触发特定 Firebase 实时数据库实例的事件的函数

functions.database.instance('my-app-db-2').ref('/foo/bar')

使用数据库实例的名称就可以了,不需要url。 functions.database.ref 在没有实例的情况下使用会监视事件的默认实例。

【讨论】:

以上是关于如何在 Cloud Functions for Firebase 中访问多个实时数据库实例的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Cloud Functions for Firebase 获取子值的键?

如何在 Cloud Functions for Firebase 中发出 HTTP 请求?

如何在 Cloud Functions for Firebase 中使 HTTP 请求异步/等待?

如何在 PC 上本地测试 Cloud Functions for Firebase

如何使用 Firestore 在 Cloud Functions for Firebase 中获取服务器时间戳?

如何在 Cloud Functions for Firebase 中访问多个实时数据库实例