掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
觸發(fā)器是一種響應(yīng)特定服務(wù)器端事件(例如將數(shù)據(jù)保存到特定集合時)執(zhí)行操作的方法。 這些通常有兩種情況。

成都創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站制作、成都做網(wǎng)站、啟東網(wǎng)絡(luò)推廣、重慶小程序開發(fā)、啟東網(wǎng)絡(luò)營銷、啟東企業(yè)策劃、啟東品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;成都創(chuàng)新互聯(lián)為所有大學生創(chuàng)業(yè)者提供啟東建站搭建服務(wù),24小時服務(wù)熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com
觸發(fā)器針對特定的集合(例如 ?EthTransactions?)進行操作。 例如,要在轉(zhuǎn)移特定 NFT 時將訂單對象的狀態(tài)更新為“已售出”,您可以在 ?EthNFTTransfers ?上定義 ?afterSave ?觸發(fā)器。 每次將新條目添加到 ?EthNFTTransfers ?集合時都會調(diào)用觸發(fā)器,您可以檢查它是否與其中一個未結(jié)訂單匹配。
測試網(wǎng)和主網(wǎng)上的交易可能需要一段時間才能得到確認。 當 Moralis 檢測到處于未確認狀態(tài)的新交易(或事件)時,這些交易將被放入帶有confirmed:true集合中。 當交易被確認時,狀態(tài)更新為confirmed:true。
這意味著如果您在集合上定義 ?afterSave ?觸發(fā)器,則觸發(fā)器可以被觸發(fā)兩次——一次為confirmed:false,再次為confirmed:true。 任何具有confirmed屬性的集合都可能發(fā)生這種情況。 考慮到這種行為,編寫您的觸發(fā)器回調(diào)函數(shù)。 如果觸發(fā)器在其他集合中創(chuàng)建條目,則這可能導致重復條目或計算中的重復計數(shù)等。
可以通過使用 ?request.object? 獲取觸發(fā)觸發(fā)器的對象來檢查確認狀態(tài)。
Moralis.Cloud.afterSave("EthTransactions", async function (request) {
const confirmed = request.object.get("confirmed");
if (confirmed) {
// do something
} else {
// handle unconfirmed case
}
});?
Ganache?和 ?Hardhat?僅在進行交易時處理新塊。 這意味著,如果您鑄造新的 ?NFT?或進行代幣轉(zhuǎn)移,這些交易可能會卡在待處理表中。 一次確認后,這些將被移出待處理。
在云中運行代碼的另一個原因是強制執(zhí)行特定的數(shù)據(jù)格式。 例如,您可能同時擁有一個 Android 和 iOS 應(yīng)用程序,并且您希望驗證每個應(yīng)用程序的數(shù)據(jù)。 無需為每個客戶端環(huán)境編寫一次代碼,您可以使用云代碼只編寫一次。
數(shù)據(jù)驗證可以在觸發(fā)器的代碼中完成。
Moralis.Cloud.beforeSave("Review", (request) => {
throw "validation error";
}
});如果函數(shù)拋出,那么 ?Review ?對象將不會被保存并且客戶端會得到一個錯誤。 如果沒有拋出任何東西,對象將被正常保存。
一個有用的提示是,即使您的應(yīng)用程序有許多不同的版本,相同版本的云代碼也適用于所有版本。 因此,如果您啟動的應(yīng)用程序沒有正確檢查輸入數(shù)據(jù)的有效性,您仍然可以通過使用 ?beforeSave ?添加驗證來解決此問題。
在某些情況下,您不想丟棄無效數(shù)據(jù)。 您只想在保存之前對其進行一些調(diào)整。 ?beforeSave ?也可以處理這種情況。 您對 ?request.object? 所做的任何調(diào)整都將被保存。
在我們的電影評論示例中,我們可能希望確保評論不會太長。 一條長評論可能很難顯示。 我們可以使用 ?beforeSave ?將評論字段截斷為 140 個字符:
Moralis.Cloud.beforeSave("Review", (request) => {
const comment = request.object.get("comment");
if (comment.length > 140) {
// Truncate and add a ...
request.object.set("comment", comment.substring(0, 137) + "...");
}
});如果您想對 Moralis JavaScript SDK 中的預定義類使用 ?beforeSave?,則不應(yīng)為第一個參數(shù)傳遞字符串。 相反,您應(yīng)該傳遞類本身,例如:
Moralis.Cloud.beforeSave(
Moralis.User,
async (request) => {
// code here
}
// Validation Object or Validation Function
);在某些情況下,您可能希望在保存對象后執(zhí)行某種類型的操作,例如推送。 您可以通過使用 ?afterSave ?方法注冊處理程序來做到這一點。 例如,假設(shè)您想要跟蹤博客文章的評論數(shù)量。 您可以通過編寫如下函數(shù)來做到這一點:
const logger = Moralis.Cloud.getLogger();
Moralis.Cloud.afterSave("Comment", (request) => {
const query = new Moralis.Query("Post");
query
.get(request.object.get("post").id)
.then(function (post) {
post.increment("comments");
return post.save();
})
.catch(function (error) {
logger.error("Got an error " + error.code + " : " + error.message);
});
});在上面的示例中,客戶端將在處理程序中的承諾完成之前收到成功的響應(yīng),無論承諾如何解決。 例如,即使處理程序拋出異常,客戶端也會收到成功的響應(yīng)。 運行處理程序時發(fā)生的任何錯誤都可以在云代碼日志中找到。
在將響應(yīng)發(fā)送回客戶端后,您可以使用 ?afterSave ?處理程序執(zhí)行冗長的操作。 為了在 ?afterSave ?處理程序完成之前響應(yīng)客戶端,您的處理程序可能不會返回承諾,并且您的 ?afterSave ?處理程序可能不會使用 ?async/await?。
如果您想將 ?afterSave ?用于 Moralis JavaScript SDK 中的預定義類,則不應(yīng)為第一個參數(shù)傳遞字符串。 相反,您應(yīng)該傳遞類本身,例如:
Moralis.Cloud.afterSave(Moralis.User, async (request) => {
// code here
});保存 ?Moralis.Object? 時,您可以傳遞可在 ?Cloud Code Save Triggers? 中訪問的上下文字典。
上下文也從 ?beforeSave ?處理程序傳遞到 ?afterSave ?處理程序。 以下示例異步向正在添加到 ?Moralis.Role? 的用戶關(guān)系的用戶發(fā)送電子郵件,以便客戶端在電子郵件完成發(fā)送之前收到響應(yīng):
const beforeSave = function beforeSave(request) {
const { object: role } = request;
// Get users that will be added to the users relation.
const usersOp = role.op("users");
if (usersOp && usersOp.relationsToAdd.length > 0) {
// add the users being added to the request context
request.context = { buyers: usersOp.relationsToAdd };
}
};
const afterSave = function afterSave(request) {
const { object: role, context } = request;
if (context && context.buyers) {
const purchasedItem = getItemFromRole(role);
const promises = context.buyers.map(emailBuyer.bind(null, purchasedItem));
item.increment("orderCount", context.buyers.length);
promises.push(item.save(null, { useMasterKey: true }));
Promise.all(promises).catch(request.log.error.bind(request.log));
}
};您可以在刪除對象之前運行自定義云代碼。 您可以使用 ?beforeDelete ?方法執(zhí)行此操作。 例如,這可用于實現(xiàn)比通過 ?ACLs? 表達的內(nèi)容更復雜的受限刪除策略。 例如,假設(shè)您有一個相冊應(yīng)用程序,其中許多照片與每個相冊相關(guān)聯(lián),并且您希望阻止用戶刪除仍然有照片的相冊。 您可以通過編寫如下函數(shù)來做到這一點:
Moralis.Cloud.beforeDelete("Album", async (request) => {
const query = new Moralis.Query("Photo");
query.equalTo("album", request.object);
const count = await query.count({ useMasterKey: true });
if (count > 0) {
throw "Can't delete album if it still has photos.";
}
});如果函數(shù)拋出,?Album?對象不會被刪除,客戶端會報錯。 否則,對象將被正常刪除。
如果您想對 ?Moralis JavaScript SDK? 中的預定義類使用 ?beforeDelete?,則不應(yīng)為第一個參數(shù)傳遞字符串。 相反,您應(yīng)該傳遞類本身,例如:
Moralis.Cloud.beforeDelete(Moralis.User, async (request) => {
// code here
});在某些情況下,您可能希望在刪除對象后執(zhí)行某種類型的操作,例如推送。 您可以通過使用 ?afterDelete ?方法注冊處理程序來完成此操作。 例如,假設(shè)在刪除博客文章后,您還想刪除所有關(guān)聯(lián)的評論。 您可以通過編寫如下函數(shù)來做到這一點:
const logger = Moralis.Cloud.getLogger();
Moralis.Cloud.afterDelete("Post", (request) => {
const query = new Moralis.Query("Comment");
query.equalTo("post", request.object);
query
.find()
.then(Moralis.Object.destroyAll)
.catch((error) => {
logger.error(
"Error finding related comments " + error.code + ": " + error.message
);
});
});?afterDelete? 處理程序可以訪問通過 ?request.object? 刪除的對象。 此對象已完全提取,但無法重新提取或重新保存。
在處理程序終止后,客戶端將收到對刪除請求的成功響應(yīng),無論 ?afterDelete ?是如何終止的。 例如,即使處理程序拋出異常,客戶端也會收到成功的響應(yīng)。 運行處理程序時發(fā)生的任何錯誤都可以在云代碼日志中找到。
如果您想對 ?Moralis JavaScript SDK? 中的預定義類使用 ?afterDelete?,則不應(yīng)為第一個參數(shù)傳遞字符串。 相反,您應(yīng)該傳遞類本身,例如:
Moralis.Cloud.afterDelete(Moralis.User, async (request) => {
// code here
});使用 ?beforeSaveFile ?方法,您可以在保存任何文件之前運行自定義云代碼。 返回一個新的 ?Moralis.File? 將保存新文件,而不是客戶端發(fā)送的文件。
例如
// Changing the file name
Moralis.Cloud.beforeSaveFile(async (request) => {
const { file } = request;
const fileData = await file.getData();
const newFile = new Moralis.File("a-new-file-name.txt", { base64: fileData });
return newFile;
});
// Returning an already saved file
Moralis.Cloud.beforeSaveFile((request) => {
const { user } = request;
const avatar = user.get("avatar"); // this is a Moralis.File that is already saved to the user object
return avatar;
});
// Saving a different file from uri
Moralis.Cloud.beforeSaveFile((request) => {
const newFile = new Moralis.File("some-file-name.txt", {
uri: "www.somewhere.com/file.txt",
});
return newFile;
});向您的文件添加元數(shù)據(jù)和標簽允許您向存儲在您的存儲解決方案(即 AWS S3)中的文件添加額外的數(shù)據(jù)位。 ?beforeSaveFile ?鉤子是在文件上設(shè)置元數(shù)據(jù)和/或標簽的好地方。
注意:并非所有存儲適配器都支持元數(shù)據(jù)和標簽。 檢查您正在使用的存儲適配器的文檔以了解兼容性。
// Adding metadata and tags
Moralis.Cloud.beforeSaveFile((request) => {
const { file, user } = request;
file.addMetadata("createdById", user.id);
file.addTag("groupId", user.get("groupId"));
});?afterSaveFile ?方法是跟蹤應(yīng)用程序中存儲的所有文件的好方法。 例如:
Moralis.Cloud.afterSaveFile(async (request) => {
const { file, fileSize, user } = request;
const fileObject = new Moralis.Object("FileObject");
fileObject.set("file", file);
fileObject.set("fileSize", fileSize);
fileObject.set("createdBy", user);
const token = { sessionToken: user.getSessionToken() };
await fileObject.save(null, token);
});您可以在刪除任何文件之前運行自定義云代碼。 例如,假設(shè)您要添加只允許創(chuàng)建文件的用戶刪除文件的邏輯。 您可以使用 ?afterSaveFile ?和 ?beforeDeleteFile ?方法的組合,如下所示:
Moralis.Cloud.afterSaveFile(async (request) => {
const { file, user } = request;
const fileObject = new Moralis.Object('FileObject');
fileObject.set('fileName', file.name());
fileObject.set('createdBy', user);
await fileObject.save(null, { useMasterKey: true );
});
Moralis.Cloud.beforeDeleteFile(async (request) => {
const { file, user } = request;
const query = new Moralis.Query('FileObject');
query.equalTo('fileName', file.name());
const fileObject = await query.first({ useMasterKey: true });
if (fileObject.get('createdBy').id !== user.id) {
throw 'You do not have permission to delete this file';
}
});在上面的 ?beforeDeleteFile ?示例中,?FileObject ?集合用于跟蹤應(yīng)用程序中保存的文件。 成功刪除文件后,?afterDeleteFile ?觸發(fā)器是清理這些對象的好地方。
Moralis.Cloud.afterDeleteFile(async (request) => {
const { file } = request;
const query = new Moralis.Query("FileObject");
query.equalTo("fileName", file.name());
const fileObject = await query.first({ useMasterKey: true });
await fileObject.destroy({ useMasterKey: true });
});在某些情況下,您可能希望轉(zhuǎn)換傳入查詢、添加額外限制或增加默認限制、添加額外包含或?qū)⒔Y(jié)果限制為鍵的子集。 您可以使用 ?beforeFind ?觸發(fā)器來執(zhí)行此操作。
例如
// Properties available
Moralis.Cloud.beforeFind("MyObject", (req) => {
let query = req.query; // the Moralis.Query
let user = req.user; // the user
let triggerName = req.triggerName; // beforeFind
let isMaster = req.master; // if the query is run with masterKey
let isCount = req.count; // if the query is a count operation
let logger = req.log; // the logger
let installationId = req.installationId; // The installationId
});
// Selecting keys
Moralis.Cloud.beforeFind("MyObject", (req) => {
let query = req.query; // the Moralis.Query
// Force the selection on some keys
query.select(["key1", "key2"]);
});
// Asynchronous support
Moralis.Cloud.beforeFind("MyObject", (req) => {
let query = req.query;
return aPromise().then((results) => {
// do something with the results
query.containedIn("key", results);
});
});
// Returning a different query
Moralis.Cloud.beforeFind("MyObject", (req) => {
let query = req.query;
let otherQuery = new Moralis.Query("MyObject");
otherQuery.equalTo("key", "value");
return Moralis.Query.or(query, otherQuery);
});
// Rejecting a query
Moralis.Cloud.beforeFind("MyObject", (req) => {
// throw an error
throw new Moralis.Error(101, "error");
// rejecting promise
return Promise.reject("error");
});
// Setting the read preference for a query
Moralis.Cloud.beforeFind("MyObject2", (req) => {
req.readPreference = "SECONDARY_PREFERRED";
req.subqueryReadPreference = "SECONDARY";
req.includeReadPreference = "PRIMARY";
});如果要將 ?beforeFind ?用于 ?Moralis JavaScript SDK? 中的預定義類,則不應(yīng)為第一個參數(shù)傳遞字符串。 相反,您應(yīng)該傳遞類本身,例如:
Moralis.Cloud.beforeFind(Moralis.User, async (request) => {
// code here
});在某些情況下,您可能希望在將查詢結(jié)果發(fā)送到客戶端之前對其進行操作。 您可以使用 ?afterFind ?觸發(fā)器執(zhí)行此操作。
Moralis.Cloud.afterFind("MyCustomClass", async (request) => {
// code here
});如果要將 ?afterFind ?用于 ?Moralis JavaScript SDK? 中的預定義類,則不應(yīng)為第一個參數(shù)傳遞字符串。 相反,您應(yīng)該傳遞類本身,例如:
Moralis.Cloud.afterFind(Moralis.User, async (request) => {
// code here
});有時您可能希望對登錄請求運行自定義驗證。 ?beforeLogin ?觸發(fā)器可用于阻止帳戶登錄(例如,如果他們被禁止),記錄登錄事件以進行分析,如果登錄發(fā)生在不尋常的 IP 地址上,則通過電子郵件通知用戶等等。
Moralis.Cloud.beforeLogin(async (request) => {
const { object: user } = request;
if (user.get("isBanned")) {
throw new Error("Access denied, you have been banned.");
}
});需要注意的一些注意事項
promise?解決。 beforeLogin ?成功完成之后,才向用戶提供會話。 Moralis.User? 上的 ?afterSave ?一樣,除非明確保存,否則它不會將突變保存到用戶。觸發(fā)器將運行
authProvider ?登錄時。觸發(fā)器不會運行
有時您可能希望在用戶注銷后運行操作。 例如,?afterLogout ?觸發(fā)器可用于用戶注銷后的清理操作。 觸發(fā)器包含已在注銷時刪除的會話對象。 從此會話對象中,您可以確定注銷以執(zhí)行用戶特定任務(wù)的用戶。
Moralis.Cloud.afterLogout(async (request) => {
const { object: session } = request;
const user = session.get("user");
user.set("isOnline", false);
user.save(null, { useMasterKey: true });
});需要注意的一些注意事項
afterDelete ?觸發(fā)器一樣,請求中包含的 ?_Session? 對象已被刪除。觸發(fā)器將運行
_Session? 對象時。觸發(fā)器不會運行
_Session? 對象。 _Session? 對象被刪除,而用戶沒有通過調(diào)用 SDK 的 logout 方法注銷。您可以在用戶嘗試使用 ?beforeConnect ?方法連接到您的 LiveQuery 服務(wù)器之前運行自定義云代碼。 例如,這可用于僅允許已登錄的用戶連接到 LiveQuery 服務(wù)器。
Moralis.Cloud.beforeConnect((request) => {
if (!request.user) {
throw "Please login before you attempt to connect.";
}
});大多數(shù)情況下,?connect ?事件在客戶端第一次調(diào)用 ?subscribe ?時被調(diào)用。 如果這是您的用例,您可以使用此事件偵聽錯誤。
const logger = Moralis.Cloud.getLogger();
Moralis.LiveQuery.on("error", (error) => {
logger.info(error);
});在某些情況下,您可能希望轉(zhuǎn)換傳入的訂閱查詢。 示例包括添加額外限制、增加默認限制、添加額外包含或?qū)⒔Y(jié)果限制為鍵的子集。 您可以使用 ?beforeSubscribe ?觸發(fā)器來執(zhí)行此操作。
Moralis.Cloud.beforeSubscribe("MyObject", (request) => {
if (!request.user.get("Admin")) {
throw new Moralis.Error(
101,
"You are not authorized to subscribe to MyObject."
);
}
let query = request.query; // the Moralis.Query
query.select("name", "year");
});在某些情況下,您可能希望在將實時查詢的結(jié)果發(fā)送到客戶端之前對其進行操作。 您可以使用 ?afterLiveQueryEvent ?觸發(fā)器執(zhí)行此操作。
例如
// Changing values on object and original
Moralis.Cloud.afterLiveQueryEvent("MyObject", (request) => {
const object = request.object;
object.set("name", "***");
const original = request.original;
original.set("name", "yolo");
});
// Prevent LiveQuery trigger unless 'foo' is modified
Moralis.Cloud.afterLiveQueryEvent("MyObject", (request) => {
const object = request.object;
const original = request.original;
if (!original) {
return;
}
if (object.get("foo") != original.get("foo")) {
request.sendEvent = false;
}
});默認情況下,?MoralisLiveQuery ?不執(zhí)行需要額外數(shù)據(jù)庫操作的查詢。 這是為了讓您的 ?Moralis Server? 盡可能快速和高效。 如果您需要此功能,您可以在 ?afterLiveQueryEvent ?中執(zhí)行這些功能。
// Including an object on LiveQuery event, on update only.
Moralis.Cloud.afterLiveQueryEvent("MyObject", async (request) => {
if (request.event != "update") {
request.sendEvent = false;
return;
}
const object = request.object;
const pointer = object.get("child");
await pointer.fetch();
});
// Extend matchesQuery functionality to LiveQuery
Moralis.Cloud.afterLiveQueryEvent("MyObject", async (request) => {
if (request.event != "create") {
return;
}
const query = request.object.relation("children").query();
query.equalTo("foo", "bart");
const first = await query.first();
if (!first) {
request.sendEvent = false;
}
});afterLiveQueryEvent ?觸發(fā)器完成之前,不會觸發(fā)實時查詢事件。 確保觸發(fā)器內(nèi)的任何功能都有效且具有限制性,以防止出現(xiàn)瓶頸。有時您可能希望監(jiān)視要與第三方(例如“?Datadog?”)一起使用的實時查詢事件。 ?onLiveQueryEvent ?觸發(fā)器可以記錄觸發(fā)的事件、連接的客戶端數(shù)量、訂閱數(shù)量和錯誤。
Moralis.Cloud.onLiveQueryEvent(
({
event,
client,
sessionToken,
useMasterKey,
installationId,
clients,
subscriptions,
error,
}) => {
if (event !== "ws_disconnect") {
return;
}
// Do your magic
}
);“connect”與“ws_connect”不同,前者意味著客戶端完成了Moralis Live Query協(xié)議定義的連接過程,其中“ws_connect”只是意味著創(chuàng)建了一個新的websocket。

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流