繁体   English   中英

Firebase 实时数据库多文档更新失败

[英]Firebase Realtime DB multi-document update failing

我需要更新实时数据库中的许多文档(30 万+)。 我已经使用 Firebase Admin SDK 编写了一个 js 代码来执行此操作。 当文档较少(~3000)时,此代码可以正常工作。 但是当存在大量文档(使用 14k 测试)且 js 堆出 memory 时会失败。

我的js代码:-

const firebaseAuth = require('./firebase/firebase.admin')

async function main() {

    await firebaseAuth.firebaseAuthInit();

    let db = firebaseAuth.admin.database();
    let usersRef = db.ref("users");

    return usersRef.once("value").then(async function (snapshot) {
        let updates = [];
        let usersCount = 0;
        
        snapshot.forEach(async function (userSnapshot) {
            let user = userSnapshot.val();
            let userKey = userSnapshot.key;
            if (user.hasOwnProperty('Settings')) {

                 //let promise = await usersRef.child(userKey).get();
                 let promise = usersRef.child(userKey).update({
                     'Settings': null
                 }).then(
                     console.log(`Removed Settings attribute for user: ${userKey}`)
                 )
                updates.push(promise);
            }
            usersCount++;
        })
        
        let settingRemoved = (await Promise.all(updates)).length;
        console.log(`Numbers of Users: ${usersCount}. Total no of User Settings Deleted: ${settingRemoved}`)

    }, function (error) {
        console.error(error);
    }).then(function () {
        process.exit()
    })

}

main()

我得到的错误是:

<--- Last few GCs --->

[683:0x5cea240]    76471 ms: Scavenge 2037.5 (2062.5) -> 2035.2 (2063.3) MB, 11.3 / 0.0 ms  (average mu = 0.185, current mu = 0.148) allocation failure
[683:0x5cea240]    76484 ms: Scavenge 2038.4 (2063.3) -> 2036.1 (2064.0) MB, 6.1 / 0.0 ms  (average mu = 0.185, current mu = 0.148) allocation failure
[683:0x5cea240]    76507 ms: Scavenge 2039.0 (2064.0) -> 2036.9 (2072.8) MB, 7.8 / 0.0 ms  (average mu = 0.185, current mu = 0.148) allocation failure


<--- JS stacktrace --->

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0xb200e0 node::Abort() [node]
 2: 0xa3c157 node::FatalError(char const*, char const*) [node]
 3: 0xd083ae v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xd08727 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
 5: 0xee9785  [node]
 6: 0xeea2cc  [node]
 7: 0xef8269 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node]
 8: 0xefb535 v8::internal::Heap::HandleGCRequest() [node]
 9: 0xe8fc17 v8::internal::StackGuard::HandleInterrupts() [node]
10: 0x12364e2 v8::internal::Runtime_StackGuardWithGap(int, unsigned long*, v8::internal::Isolate*) [node]
11: 0x1640839  [node]
Aborted (core dumped)

该问题可能是由于将所有承诺推送到单个数组而导致的,这会导致堆 memory 溢出。

有什么办法可以避免这种情况吗? 我找不到任何方法可以分批或按顺序执行这些操作(但是,如果 300k 记录的运行时间超过 5 分钟,则按顺序可能不可行)。

节点版本:16.4

但是当存在大量文档(使用 14k 测试)且 js 堆出 memory 时会失败。

这是预期的行为,因为 14k 代表大量数据,实际上并不适合 memory。 有两种方法可以解决这种情况。

第一个是仅按需更新数据。 假设您有一个特定页面要显示一些数据,其中一个字段不应该再存在,另一个应该更新一些内容。 现在,您应该仅在用户打开页面时检查这些字段。 因此,如果第一个字段没有被删除而另一个字段没有被更新,则执行删除和更新操作,然后显示数据,否则只显示数据。 这样,您将仅在实际需要时更新数据。 因此,您很可能永远不会更新所有这 30 万多个节点,因为并非所有用户都会访问该屏幕。

第二种解决方案是创建一个云 Function 并通过执行多个同时更新来开始更新所有数据。 但在开始之前,请尝试检查实时数据库限制

除了 Alex 建议的两种方法之外,第三种选择是分块更新Users 假设您决定一次处理 100 个用户:

  1. 使用ref.orderByKey().limitToFirst(100)加载前 100 个用户。
  2. 更新这些用户,并记下最后一个键。
  3. 使用ref.orderByKey().startAfter(theLastKey).limitToFirst(100)加载接下来的 100 个用户。
  4. 重复直到您不再从数据库中获得响应,这意味着所有更新都已完成。

或者,由于您要删除一个节点,您还可以使用它来过滤您仍需要更新的子节点。 这样流程就变成了:

  1. 使用ref.orderByChild("Settings").limitToFirst(100)加载前 100 个用户。
  2. 更新这些用户。
  3. 重复直到您不再从数据库中获得响应,这意味着所有更新都已完成。

除了更简单之外,这还有一个优点,即您不会读取已经没有Settings属性的节点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM