![](/img/trans.png)
[英]How to set Firebase cloud functions to route to Firestore instead of Realtime Database
[英]Firebase realtime database transaction and cloud functions
我在 Firebase 實時數據庫中有一個列表,結構如下:
list: {
change: {
rate: integer,
last: Date
},
lock: string,
elements: {
...
},
size: integer
}
客戶端只將元素添加到列表中。 元素的子元素上有一個由onCreate
事件觸發的雲函數。 它事務性地增加數據庫中的list.size
,然后對可能涉及刪除所有或部分子項的元素執行計算。 還有另一個雲函數由元素的子元素上的onDelete
事件觸發,它只會事務性地減少數據庫中的list.size
。 問題是計數器在一段時間后變得不准確。 有時它顯示列表中的更多元素,有時更少。 以下是[改編]代碼:
exports.element_add = functions.database.ref('/list/elements/{element}).onCreate(
(snapshot, context) => {
const elements = snapshot.ref.parent;
return new Promise(
(resolve, reject) => {
const start = new Date().getTime();
async.waterfall(
[
// read and write to list.change
// ...
(next) => {
// increment list size
_changeSize(elements.parent, +1, 1, next)
},
// acquire lock if required and do calculations on list elements
// ...
],
// finally
function (e) {
// release the lock
// ...
// handle errors
if (e)
return reject(e);
resolve();
}
);
});
});
exports.element_remove = functions.database.ref('/list/elements/{element}).onDelete(
(snapshot, context) => {
const elements = snapshot.ref.parent;
return new Promise(
function (resolve, reject) {
_changeSize(elements.parent, -1, 1,
function (e) {
if (e)
return reject(e);
resolve();
}
)
}
)
});
function _changeSize(list, delta, attempt, done) {
list.child('size').transaction(
// update
(size) => {
if (size === null)
return null;
return size + delta;
},
// finally
(e, committed, snapshot) {
if (e) {
console.error(`size transaction error: ${e}, retrying in 1 sec`);
// try again
return setTimeout(_changeSize, 1000, list, delta, attempt + 1, done);
}
console.log(committed ? `new list size is ${snapshot.val()}` : 'list size was not updated');
// return new size if committed
done(null, committed ? snapshot.val() : undefined);
},
// do not apply locally
false
);
}
除了上面的兩個雲函數之外,沒有其他實體使用list.size
。 問題是為什么list.size
的值與list.elements
不同步?
2020 年 2 月 26 日更新:顯然不止一次收到一些 onCreate/onDelete 事件! 我們已經觀察到它們在雲函數實例之間的傳播甚至達到了 3 次。 這是正常行為還是我們做錯了什么?
您必須使用實時數據庫事務。
遞增如下:
exports.element_add = functions.database.ref('/list/elements/{element}').onCreate(
(snapshot, context) => {
const sizeRef = admin
.database()
.ref('/list/size');
return sizeRef
.transaction(current_value => {
return (current_value || 0) + 1;
});
});
並如下遞減:
exports.element_delete = functions.database.ref('/list/elements/{element}').onDelete(
(snapshot, context) => {
const sizeRef = admin
.database()
.ref('/list/size');
return sizeRef
.transaction(current_value => {
if (current_value > 0) {
return current_value - 1;
} else {
//Normally we should never reach this line...
return null;
}
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.