这个问题已经困扰我好几天了,但我似乎无法解决它。当我的云功能更新某个 Firestore 文档时,例如/user/1/contact/2
被快速连续多次调用,目标文档被清空/删除。然而,当只进行一次调用时,它工作得很好。日志、审计日志和调试日志显示该函数像这样Function execution took 8308 ms, finished with status: 'ok'
成功并且不会抛出任何错误。
有谁知道是什么导致了这种情况以及我如何防止这种情况发生?
提前致谢。
编辑 1:
这是我的代码(为了可读性稍微整理了一下):
const language = require('@google-cloud/language');
const client = new language.LanguageServiceClient();
const axios = require('axios')
const Firestore = require('@google-cloud/firestore');
const admin = require('firebase-admin');
const FormData = require("form-data");
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
const db = admin.firestore();
/**
* Triggered by a change to a Firestore document.
*
* @param {!Object} event Event payload.
* @param {!Object} context Metadata for the event.
*/
exports.helloFirestore = async (event, context) => {
if (event.updateMask && Object.keys(event.updateMask).length) {
console.log(`\nupdateMask:`);
console.log(JSON.stringify(event.updateMask, null, 2));
}
var companyId = context.params.companyId
var functionId = context.params.functionId
var vacancyId = context.params.vacancyId
var functionDoc = db.collection("companies").doc(companyId).collection('functions').doc(functionId).collection('vacancies').doc(vacancyId);
var publicFunctionDoc = db.collection("companies").doc(companyId).collection('public_functions').doc(functionId).collection('vacancies').doc(vacancyId);
var job = null;
var publicJob = null;
var generalJob = null;
var company = null;
var ignoredIds = [];
var users = [];
await functionDoc.get().then(function (doc) {
if (doc.exists) {
job = doc.data();
job.id = doc.id;
}
});
await publicFunctionDoc.get().then(function (doc) {
if (doc.exists) {
publicJob = doc.data();
publicJob.id = doc.id;
}
});
await db.collection("companies").doc(companyId).get().then(function (doc) {
if (doc.exists) {
company = doc.data();
company.id = doc.id;
}
});
await db.collection("companies").doc(companyId).collection('functions').doc(functionId).get().then(function (doc) {
if (doc.exists) {
generalJob = doc.data();
}
});
await db.collection('users').where('preferences.active', '==', true).where('preferences.locked', '==', false).get().then(function (snapshot) {
snapshot.forEach(user => {
users.push({
...user.data(),
id: user.id
})
})
});
await db.collection('users').where('preferences.active', '==', true).where('preferences.owner', '==', company.id).get().then(function (snapshot) {
snapshot.forEach(user => {
users.push({
...user.data(),
id: user.id
})
})
});
if (job.interacted == undefined || job.interacted == null) {
job.interacted = [];
}
if (job.ignored == undefined || job.ignored == null) {
job.ignored = [];
}
if (generalJob.ignored == undefined || generalJob.ignored == null) {
generalJob.ignored = [];
}
if (company.ignored == undefined || company.ignored == null) {
company.ignored = [];
}
if (company.banned == undefined || company.banned == null) {
company.banned = [];
}
ignoredIds = job.ignored.concat(job.banned, company.ignored, company.banned);
users = users.filter(user => {
if (ignoredIds.indexOf(user.id) == -1) {
return true;
}
return false;
});
if (job != null && users.length > 0) {
match(job, users, companyId, functionId, vacancyId, functionDoc, publicJob, company);
}
};
// Matching v1.0
function match(job, people, companyId, functionId, vacancyId, functionDoc, publicJob, company) {
if (job.matches == null || job.matches == undefined) {
job.matches = [];
}
if (job.hired == null || job.hired == undefined) {
job.hired = [];
}
people.forEach(user => {
if (user.matches2 == null || user.matches2 == undefined) {
user.matches2 = [];
}
if (user.skills2) {
if (user.matches == undefined || user.matches == null) {
user.matches = [];
}
if (score > 0) {
if (user.matches2 == undefined || user.matches2 == null) {
user.matches2 = [];
}
var result = user.matches2.find(obj => {
return obj.job == functionId
})
if (result == undefined) {
var vacancy = {
job: functionId,
score: score,
data: publicJob,
company: company,
doc: functionDoc,
applied: false,
date: new Date()
};
user.matches2.push(vacancy);
saveVacancyForUser(user.id, vacancy);
if (user.preferences == null || user.preferences == undefined) {
user.preferences = {
annonymous: false
};
}
if (user.preferences.annonymous != null && user.preferences.annonymous != undefined) {
user.profile.annonymous = user.preferences.annonymous
}
}
var result = job.matches.find(obj => {
return obj.user.id == user.id
})
var result2 = job.hired.find(obj => {
return obj.user.id == user.id
})
if (result == undefined && result2 == undefined) {
job.matches.push({
user: user,
score: score
});
}
}
saveUserDoc(user.id, user)
}
})
if (job.matches.length > 0) {
console.log(job.matches.length);
var obj = {};
for (var i = 0, len = job.matches.length; i < len; i++) {
obj[job.matches[i]['user']['id']] = job.matches[i];
}
job.matches = new Array();
for (var key in obj) {
job.matches.push(obj[key]);
}
saveVacancyData(companyId, functionId, vacancyId, job)
}
}
function unique(data, key) {
console.log("key:::::::" + key)
return [
...new Map(
data.map(x => [key(x), x])
).values()
]
}
async function saveVacancyForUser(uid, vacancy){
var userVacancyDoc = db.collection("users").doc(uid).collection('vacancies');
await userVacancyDoc.add(vacancy).then(function () {
console.log("Document successfully written! --- uservacancy");
})
.catch(function (error) {
console.error("Error writing document: ", error);
});
}
async function saveUserDoc(uid, user){
var userDoc = db.collection("users").doc(uid);
await userDoc.set(user, {
merge: true
}).then(function () {
console.log("Document successfully written! ---- userDoc");
})
.catch(function (error) {
console.error("Error writing document: ", error);
});
}
async function saveVacancyData(companyId, functionId, vacancyId, job){
var functionDoc = db.collection("companies").doc(companyId).collection('functions').doc(functionId).collection('vacancies').doc(vacancyId);
await functionDoc.set(job, {
merge: false
}).then(function () {
console.log("Document successfully written! --- job");
console.log("hey")
})
.catch(function (error) {
console.error("Error writing document: ", error);
});
}