I am trying to implement Firebase's distributed counter extension in a cloud function. The idea is to detect when a document is created, then a counter inside a document is added. Below is my cloud function:
exports.bookmark_increment = functions.firestore.document('questions/{question_id}/bookmarks/{user_uid}')
.onCreate(async (snap, context) => {
// compiled client sample code for increment counter
var sharded = function(t) { var e = {}; function r(n) { if (e[n]) return e[n].exports; var o = e[n] = { i: n, l: !1, exports: {} }; return t[n].call(o.exports, o, o.exports, r), o.l = !0, o.exports } return r.m = t, r.c = e, r.d = function(t, e, n) { r.o(t, e) || Object.defineProperty(t, e, { enumerable: !0, get: n }) }, r.r = function(t) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(t, "__esModule", { value: !0 }) }, r.t = function(t, e) { if (1 & e && (t = r(t)), 8 & e) return t; if (4 & e && "object" == typeof t && t && t.__esModule) return t; var n = Object.create(null); if (r.r(n), Object.defineProperty(n, "default", { enumerable: !0, value: t }), 2 & e && "string" != typeof t) for (var o in t) r.d(n, o, function(e) { return t[e] }.bind(null, o)); return n }, r.n = function(t) { var e = t && t.__esModule ? function() { return t.default } : function() { return t }; return r.d(e, "a", e), e }, r.o = function(t, e) { return Object.prototype.hasOwnProperty.call(t, e) }, r.p = "", r(r.s = 2) }([function(t, e) { var r = "undefined" != typeof crypto && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || "undefined" != typeof msCrypto && "function" == typeof window.msCrypto.getRandomValues && msCrypto.getRandomValues.bind(msCrypto); if (r) { var n = new Uint8Array(16); t.exports = function() { return r(n), n } } else { var o = new Array(16); t.exports = function() { for (var t, e = 0; e < 16; e++)0 == (3 & e) && (t = 4294967296 * Math.random()), o[e] = t >>> ((3 & e) << 3) & 255; return o } } }, function(t, e) { for (var r = [], n = 0; n < 256; ++n)r[n] = (n + 256).toString(16).substr(1); t.exports = function(t, e) { var n = e || 0, o = r; return [o[t[n++]], o[t[n++]], o[t[n++]], o[t[n++]], "-", o[t[n++]], o[t[n++]], "-", o[t[n++]], o[t[n++]], "-", o[t[n++]], o[t[n++]], "-", o[t[n++]], o[t[n++]], o[t[n++]], o[t[n++]], o[t[n++]], o[t[n++]]].join("") } }, function(t, e, r) { "use strict"; var n = this && this.__awaiter || function(t, e, r, n) { return new (r || (r = Promise))(function(o, i) { function s(t) { try { a(n.next(t)) } catch (t) { i(t) } } function u(t) { try { a(n.throw(t)) } catch (t) { i(t) } } function a(t) { t.done ? o(t.value) : new r(function(e) { e(t.value) }).then(s, u) } a((n = n.apply(t, e || [])).next()) }) }, o = this && this.__generator || function(t, e) { var r, n, o, i, s = { label: 0, sent: function() { if (1 & o[0]) throw o[1]; return o[1] }, trys: [], ops: [] }; return i = { next: u(0), throw: u(1), return: u(2) }, "function" == typeof Symbol && (i[Symbol.iterator] = function() { return this }), i; function u(i) { return function(u) { return function(i) { if (r) throw new TypeError("Generator is already executing."); for (; s;)try { if (r = 1, n && (o = 2 & i[0] ? n.return : i[0] ? n.throw || ((o = n.return) && o.call(n), 0) : n.next) && !(o = o.call(n, i[1])).done) return o; switch (n = 0, o && (i = [2 & i[0], o.value]), i[0]) { case 0: case 1: o = i; break; case 4: return s.label++, { value: i[1], done: !1 }; case 5: s.label++, n = i[1], i = [0]; continue; case 7: i = s.ops.pop(), s.trys.pop(); continue; default: if (!(o = (o = s.trys).length > 0 && o[o.length - 1]) && (6 === i[0] || 2 === i[0])) { s = 0; continue } if (3 === i[0] && (!o || i[1] > o[0] && i[1] < o[3])) { s.label = i[1]; break } if (6 === i[0] && s.label < o[1]) { s.label = o[1], o = i; break } if (o && s.label < o[2]) { s.label = o[2], s.ops.push(i); break } o[2] && s.ops.pop(), s.trys.pop(); continue }i = e.call(t, s) } catch (t) { i = [6, t], n = 0 } finally { r = o = 0 } if (5 & i[0]) throw i[1]; return { value: i[0] ? i[1] : void 0, done: !0 } }([i, u]) } } }; Object.defineProperty(e, "__esModule", { value: !0 }); var i = r(3), s = "_counter_shards_", u = "FIRESTORE_COUNTER_SHARD_ID", a = function() { function t(t, e) { this.doc = t, this.field = e, this.db = null, this.shardId = "", this.shards = {}, this.notifyPromise = null, this.db = t.firestore, this.shardId = function(t) { var e = new RegExp("(?:^|; )" + encodeURIComponent(t) + "=([^;]*)").exec(document.cookie); if (e) return e[1]; var r = i.v4(), n = new Date; n.setTime(n.getTime() + 2592e6); var o = "; expires=" + n.toUTCString(); return document.cookie = encodeURIComponent(t) + "=" + r + o + "; path=/", r }(u); var r = t.collection(s); this.shards[t.path] = 0, this.shards[r.doc(this.shardId).path] = 0, this.shards[r.doc("\t" + this.shardId.substr(0, 4)).path] = 0, this.shards[r.doc("\t\t" + this.shardId.substr(0, 3)).path] = 0, this.shards[r.doc("\t\t\t" + this.shardId.substr(0, 2)).path] = 0, this.shards[r.doc("\t\t\t\t" + this.shardId.substr(0, 1)).path] = 0 } return t.prototype.get = function(t) { return n(this, void 0, void 0, function() { var e, r = this; return o(this, function(i) { switch (i.label) { case 0: return e = Object.keys(this.shards).map(function(e) { return n(r, void 0, void 0, function() { return o(this, function(r) { switch (r.label) { case 0: return [4, this.db.doc(e).get(t)]; case 1: return [2, r.sent().get(this.field) || 0] } }) }) }), [4, Promise.all(e)]; case 1: return [2, i.sent().reduce(function(t, e) { return t + e }, 0)] } }) }) }, t.prototype.onSnapshot = function(t) { var e = this; Object.keys(this.shards).forEach(function(r) { e.db.doc(r).onSnapshot(function(r) { e.shards[r.ref.path] = r.get(e.field) || 0, null === e.notifyPromise && (e.notifyPromise = function(t) { return n(this, void 0, void 0, function() { var e = this; return o(this, function(r) { return [2, new Promise(function(r) { return n(e, void 0, void 0, function() { var e = this; return o(this, function(i) { return setTimeout(function() { return n(e, void 0, void 0, function() { var e; return o(this, function(n) { return e = t(), r(e), [2] }) }) }, 0), [2] }) }) })] }) }) }(function() { var r = Object.values(e.shards).reduce(function(t, e) { return t + e }, 0); t({ exists: !0, data: function() { return r } }), e.notifyPromise = null })) }) }) }, t.prototype.incrementBy = function(t) { var e = firebase.firestore.FieldValue.increment(t), r = this.field.split(".").reverse().reduce(function(t, e) { var r; return (r = {})[e] = t, r }, e); return this.doc.collection(s).doc(this.shardId).set(r, { merge: !0 }) }, t.prototype.shard = function() { return this.doc.collection(s).doc(this.shardId) }, t }(); e.Counter = a }, function(t, e, r) { var n = r(4), o = r(5), i = o; i.v1 = n, i.v4 = o, t.exports = i }, function(t, e, r) { var n, o, i = r(0), s = r(1), u = 0, a = 0; t.exports = function(t, e, r) { var c = e && r || 0, f = e || [], d = (t = t || {}).node || n, l = void 0 !== t.clockseq ? t.clockseq : o; if (null == d || null == l) { var h = i(); null == d && (d = n = [1 | h[0], h[1], h[2], h[3], h[4], h[5]]), null == l && (l = o = 16383 & (h[6] << 8 | h[7])) } var p = void 0 !== t.msecs ? t.msecs : (new Date).getTime(), v = void 0 !== t.nsecs ? t.nsecs : a + 1, y = p - u + (v - a) / 1e4; if (y < 0 && void 0 === t.clockseq && (l = l + 1 & 16383), (y < 0 || p > u) && void 0 === t.nsecs && (v = 0), v >= 1e4) throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); u = p, a = v, o = l; var b = (1e4 * (268435455 & (p += 122192928e5)) + v) % 4294967296; f[c++] = b >>> 24 & 255, f[c++] = b >>> 16 & 255, f[c++] = b >>> 8 & 255, f[c++] = 255 & b; var m = p / 4294967296 * 1e4 & 268435455; f[c++] = m >>> 8 & 255, f[c++] = 255 & m, f[c++] = m >>> 24 & 15 | 16, f[c++] = m >>> 16 & 255, f[c++] = l >>> 8 | 128, f[c++] = 255 & l; for (var g = 0; g < 6; ++g)f[c + g] = d[g]; return e || s(f) } }, function(t, e, r) { var n = r(0), o = r(1); t.exports = function(t, e, r) { var i = e && r || 0; "string" == typeof t && (e = "binary" === t ? new Array(16) : null, t = null); var s = (t = t || {}).random || (t.rng || n)(); if (s[6] = 15 & s[6] | 64, s[8] = 63 & s[8] | 128, e) for (var u = 0; u < 16; ++u)e[i + u] = s[u]; return e || o(s) } }]);
const question_ref = db.collection('questions').doc(context.params.question_id);
// Initialize the sharded counter.
var bookmarks_count = new sharded.Counter(question_ref, "bookmarks_count");
bookmarks_count.incrementBy(1);
});
The idea is when an user bookmarks a question. It creates a new document inside the subcollection bookmarks
inside the corresponding question document. Then the function will detect the new document creation, and update the bookmark counter by one. I am trying to use the firebase's extension to do this. But somehow, the counter do not work when I deploy the function. What did I do wrong here?
await
. The firestore returns promise and you haven't handled it properly.const question_ref = await db.collection('questions').doc(context.params.question_id);
- change this line @YugueChen – KosseReferenceError: document is not defined
, and the error happens at line where I copied the sample code for Firebase for thesharded
functionvar sharded=function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:..........
I am thinking that the extension might not work in a node.js environment – Tumbling