在 Moralis 上存儲數(shù)據(jù)是圍繞 ?Moralis.Object
? 構(gòu)建的。 每個 ?Moralis.Object
? 都包含 JSON 兼容數(shù)據(jù)的鍵值對。 此數(shù)據(jù)是無模式的,這意味著您無需提前指定每個 ?Moralis.Object
? 上存在哪些鍵。 您只需設(shè)置所需的任何鍵值對,我們的后端就會存儲它們。
例如,假設(shè)您正在構(gòu)建一個角色是?Monster
?的 NFT 游戲。 單個 ?Moralis.Object
? 可以包含:
?strength
?(強度):1024,?ownerName
?(所有者名稱):“Aegon”,?canFly
?:true
鍵必須是字母數(shù)字字符串。 值可以是字符串、數(shù)字、布爾值,甚至是數(shù)組和字典——任何可以被 JSON 編碼的東西。
每個 ?Moralis.Object
? 都是具有類名的特定子類的實例,您可以使用該類名來區(qū)分不同類型的數(shù)據(jù)。 例如,我們可以將該對象稱為 ?LegendaryMonster
?。
我們建議您使用 ?
NameYourClassesLikeThis
?和 ?nameYourKeysLikeThis
?,只是為了讓您的代碼看起來更漂亮。
要創(chuàng)建新的子類,請使用 ?Moralis.Object.extend
? 方法。 任何 ?Moralis.Query
? 都將為具有相同類名的任何 ?Moralis.Object
? 返回新類的實例。 如果您熟悉 ?Backbone.Model
?,那么您已經(jīng)知道如何使用 ?Moralis.Object
?。 它旨在以相同的方式創(chuàng)建和修改。
// Simple syntax to create a new subclass of Moralis.Object.
const LegendaryMonster = Moralis.Object.extend("Monster");
// Create a new instance of that class.
const monster = new LegendaryMonster();
// Alternatively, you can use the typical Backbone syntax.
const LegendaryMonster = Moralis.Object.extend({
className: "Monster",
});
您可以向 ?Moralis.Object
? 的子類添加其他方法和屬性。
// A complex subclass of Moralis.Object
const Monster = Moralis.Object.extend(
"Monster",
{
// Instance methods
hasSuperHumanStrength: function () {
return this.get("strength") > 18;
},
// Instance properties go in an initialize method
initialize: function (attrs, options) {
this.sound = "Rawr";
},
},
{
// Class methods
spawn: function (strength) {
const monster = new Monster();
monster.set("strength", strength);
return monster;
},
}
);
const monster = Monster.spawn(200);
alert(monster.get("strength")); // Displays 200.
alert(monster.sound); // Displays Rawr.
要創(chuàng)建任何 ?Moralis Object
? 類的單個實例,您還可以直接使用 ?Moralis.Object
? 構(gòu)造函數(shù)。 ?new Moralis.Object(className)
將創(chuàng)建具有該類名的單個 Moralis 對象。
如果您已經(jīng)在代碼庫中使用 ES6。 您可以使用 ?extends
?關(guān)鍵字對 ?Moralis.Object
? 進行子類化:
class Monster extends Moralis.Object {
constructor() {
// Pass the ClassName to the Moralis.Object constructor
super("Monster");
// All other initialization
this.sound = "Rawr";
}
hasSuperHumanStrength() {
return this.get("strength") > 18;
}
static spawn(strength) {
const monster = new Monster();
monster.set("strength", strength);
return monster;
}
}
但是,使用擴展時,SDK 不會自動識別您的子類。 如果您希望從查詢返回的對象使用 ?Moralis.Object
? 的子類,則需要注冊子類,類似于我們在其他平臺上所做的。
// After specifying the Monster subclass...
Moralis.Object.registerSubclass("Monster", Monster);
同樣,您可以將擴展與 ?Moralis.User
? 一起使用。
class CustomUser extends Moralis.User {
constructor(attributes) {
super(attributes);
}
doSomething() {
return 5;
}
}
Moralis.Object.registerSubclass("_User", CustomUser);
除了查詢,?logIn
?和 ?signUp
?將返回子類 ?CustomUser
?。
const customUser = new CustomUser({ foo: "bar" });
customUser.setUsername("username");
customUser.setPassword("password");
customUser.signUp().then((user) => {
// user is an instance of CustomUser
user.doSomething(); // return 5
user.get("foo"); // return 'bar'
});
?CustomUser.logIn
? 和 ?CustomUser.signUp
? 將返回子類 ?CustomUser
?。
假設(shè)您想將上述?Monster
?保存到 ?Moralis Cloud
?。 接口類似于 ?Backbone.Model
?,包括 ?save
?方法:
你可以使用?JS
?、?React
?、?Unity
?來實現(xiàn)
const Monster = Moralis.Object.extend("Monster");
const monster = new Monster();
monster.set("strength", 1024);
monster.set("ownerName", "Aegon");
monster.set("canFly", true);
monster.save().then(
(monster) => {
// Execute any logic that should take place after the object is saved.
alert("New object created with objectId: " + monster.id);
},
(error) => {
// Execute any logic that should take place if the save fails.
// error is a Moralis.Error with an error code and message.
alert("Failed to create new object, with error code: " + error.message);
}
);
import { useNewMoralisObject } from "react-moralis";
export default function App() {
const { save } = useNewMoralisObject("Monster");
const saveObject = async () => {
const data = {
strength: 1024,
ownerName: "Aegon",
canFly: true,
};
save(data, {
onSuccess: (monster) => {
// Execute any logic that should take place after the object is saved.
alert("New object created with objectId: " + monster.id);
},
onError: (error) => {
// Execute any logic that should take place if the save fails.
// error is a Moralis.Error with an error code and message.
alert("Failed to create new object, with error code: " + error.message);
},
});
};
return <button onClick={saveObject}>Call The Code</button>;
}
using Moralis.Platform.Objects;
using MoralisWeb3ApiSdk;
using Newtonsoft.Json;
public class Monster : MoralisObject
{
public int strength { get; set; }
public string ownerName { get; set; }
public bool canFly { get; set; }
}
public async void SaveObjectToDB()
{
try {
Monster monster = MoralisInterface.GetClient().Create<Monster>();
monster.strength = 1024;
monster.ownerName = "Aegon";
monster.canFly = true;
await character.SaveAsync();
print("Created new object");
}
catch (Exception e){
print("Failed to create new object, with error code: " + e);
}
}
這段代碼運行后,您可能想知道是否真的發(fā)生了什么事。 為了確保數(shù)據(jù)已保存,您可以查看“?Moralis Dashboard
?”中的“?Data Browser
?”。 您應(yīng)該看到如下內(nèi)容:
objectId: "xWMyZ4YEGZ", strength: 1024, ownerName: "Aegon", canFly: true,
createdAt:"2011-06-10T18:33:42Z", updatedAt:"2011-06-10T18:33:42Z"
這里有兩點需要注意:
Monster
?的新類。
還有一些您不需要指定的字段是為了方便而提供的。 ?objectId
?是每個已保存對象的唯一標(biāo)識符。 ?createdAt
?和 ?updatedAt
?表示每個對象在云中創(chuàng)建和最后修改的時間。 這些字段中的每一個都由 Moralis 填寫,因此在完成保存操作之前,它們不存在于 ?Moralis.Object
? 上。
如果您愿意,您可以直接在調(diào)用中設(shè)置屬性以進行保存。
const Monster = Moralis.Object.extend("Monster");
const monster = new Monster();
monster
.save({
strength: 1024,
ownerName: "Aegon",
canFly: true,
})
.then(
(monster) => {
// The object was saved successfully.
},
(error) => {
// The save failed.
// error is a Moralis.Error with an error code and message.
}
);
默認情況下,您創(chuàng)建的類將沒有權(quán)限設(shè)置——這意味著任何人都可以將數(shù)據(jù)寫入類并從類中讀取數(shù)據(jù)。
您可以將 ?Moralis.Object
? 添加為另一個 ?Moralis.Object
? 中的屬性值。 默認情況下,當(dāng)您在父對象上調(diào)用 ?save()
? 時,所有嵌套對象都將在批處理操作中創(chuàng)建和/或保存。 此功能使管理關(guān)系數(shù)據(jù)變得非常容易,因為您不必按照任何特定順序創(chuàng)建對象。
const Child = Moralis.Object.extend("Child");
const child = new Child();
const Parent = Moralis.Object.extend("Parent");
const parent = new Parent();
parent.save({ child: child });
// Automatically the object Child is created on the server
// just before saving the Parent
在某些情況下,您可能希望阻止此默認鏈保存。 例如,當(dāng)保存一個怪物的配置文件時,它的 ?owner
?屬性指向另一個用戶擁有的帳戶,而您沒有寫入權(quán)限。 在這種情況下,將選項 ?cascadeSave
?設(shè)置為 ?false
?可能很有用:
const Monster = Moralis.Object.extend("Monster");
const monster = new Monster();
monster.set("ownerAccount", ownerAccount); // Suppose `ownerAccount` has been created earlier.
monster.save(null, { cascadeSave: false });
// Will save `teamMember` wihout attempting to save or modify `ownerAccount`
您可以傳遞一個上下文字典,該字典可在云代碼中訪問該 ?Moralis.Object
? 的 ?beforeSave
?和 ?afterSave
?觸發(fā)器。 如果您想根據(jù)不應(yīng)與 ?Moralis.Object
? 一起保存在數(shù)據(jù)庫中的臨時信息來調(diào)整云代碼觸發(fā)器中的某些操作,這將非常有用。 上下文是短暫的,因為它在云代碼觸發(fā)特定 ?Moralis.Object
? 后消失,因為它已被執(zhí)行。 例如:
const Monster = Moralis.Object.extend("Monster");
const monster = new Monster();
monster.set("species", "Dragon");
const context = { notifyMonsterGuild: true };
await monster.save(null, { context: context });
然后可以在云代碼中訪問上下文:
Moralis.Cloud.afterSave("Monster", async (req) => {
const notifyMonsterGuild = req.context.notifyMonsterGuild;
if (notifyMonsterGuild) {
// Notify the guild about new monster.
}
});
將數(shù)據(jù)保存到云端很有趣,但再次將這些數(shù)據(jù)取出會更有趣。
如果 ?Moralis.Object
? 已上傳到服務(wù)器,您可以用 ?objectId
?通過 ?Moralis.Query
? 檢索它(可以通過?JS
?、?React
?實現(xiàn)):
const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);
//get monster with id xWMyZ4YEGZ
query.get("xWMyZ4YEGZ").then(
(monster) => {
// The object was retrieved successfully.
},
(error) => {
// The object was not retrieved successfully.
// error is a Moralis.Error with an error code and message.
}
);
import { useMoralisQuery } from "react-moralis";
export default function App() {
const { fetch } = useMoralisQuery(
"Monster",
(query) => query.equalTo("objectId", "xWMyZ4YEGZ"),
[],
{ autoFetch: false }
);
const objectIdQuery = () => {
fetch({
onSuccess: (monster) => {
// The object was retrieved successfully.
},
onError: (error) => {
// The object was not retrieved successfully.
// error is a Moralis.Error with an error code and message.
},
});
};
return <button onClick={objectIdQuery}>Call The Code</button>;
}
要從 ?Moralis.Object
? 中獲取值,請使用 ?get
?方法:
const strength = monster.get("strength");
const ownerName = monster.get("ownerName");
const canFly = monster.get("canFly");
或者,可以將 ?Moralis.Object
? 的 ?attributes
?屬性視為 JavaScript 對象,甚至可以解構(gòu)。
const { strength, ownerName, canFly } = result.attributes;
四個特殊的保留值作為屬性提供,不能使用“?
get
?”方法檢索,也不能使用“?set
?”方法修改:const updatedAt = monster.updatedAt; const objectId = monster.id; const createdAt = monster.createdAt; const acl = monster.getACL();
如果您需要使用 Moralis 云中當(dāng)前的最新數(shù)據(jù)刷新已有的對象,您可以調(diào)用 ?fetch
?方法,如下所示:
myObject.fetch().then(
(myObject) => {
// The object was refreshed successfully.
},
(error) => {
// The object was not refreshed successfully.
// error is a Moralis.Error with an error code and message.
}
);
如果你需要檢查一個對象是否已經(jīng)被獲取,你可以調(diào)用 ?isDataAvailable()
? 方法:
if (!myObject.isDataAvailable()) {
await myObject.fetch();
}
更新對象很簡單。 只需在其上設(shè)置一些新數(shù)據(jù)并調(diào)用 ?save
?方法。 例如(可以通過?JS
?、?React
?實現(xiàn)):
// Create the object.
const Monster = Moralis.Object.extend("Monster");
const monster = new Monster();
monster.set("strength", 1024);
monster.set("energy", 1337);
monster.set("owner", "Aegon");
monster.set("canFly", false);
monster.set("skills", ["pwnage", "flying"]);
monster.save().then((monster) => {
// Now let's update it with some new data. In this case, only canFly and energy
// will get sent to the cloud. ownerName hasn't changed.
monster.set("canFly", true);
monster.set("energy", 1338);
return monster.save();
});
import { useNewMoralisObject } from "react-moralis";
export default function App() {
const { save } = useNewMoralisObject("Monster");
const updateObject = async () => {
const data = {
strength: 1024,
energy: 1337,
owner: "Aegon",
canFly: false,
skills: ["pwnage", "flying"],
};
save(data, {
onSuccess: (monster) => {
monster.set("canFly", true);
monster.set("strength", 1338);
return monster.save();
},
});
};
return <button onClick={updateObject}>Call The Code</button>;
}
Moralis 會自動計算出哪些數(shù)據(jù)發(fā)生了變化,因此只有?dirty
?字段會被發(fā)送到 Moralis 云。 您無需擔(dān)心壓縮您不打算更新的數(shù)據(jù)。
上面的示例包含一個常見的用例。 strength field是一個計數(shù)器,我們需要不斷更新monster的最新能量。 使用上述方法是可行的,但它很麻煩,并且如果您有多個客戶端嘗試更新同一個計數(shù)器,可能會導(dǎo)致問題。
為了幫助存儲計數(shù)器類型的數(shù)據(jù),Moralis 提供了自動增加(或減少)任何數(shù)字字段的方法。 因此,相同的更新可以重寫為:
monster.increment("energy");
monster.save();
您還可以通過將第二個參數(shù)傳遞給 ?increment
?來增加任意數(shù)量。 未指定金額時,默認使用 1。
為了幫助存儲數(shù)組數(shù)據(jù),可以使用三種操作來自動更改與給定鍵關(guān)聯(lián)的數(shù)組:
add
?將給定對象附加到數(shù)組字段的末尾。addUnique
?僅當(dāng)它尚未包含在數(shù)組字段中時才添加給定對象。 不能保證插入的位置。
remove
?從數(shù)組字段中刪除給定對象的所有實例。monster.addUnique("skills", "flying");
monster.addUnique("skills", "kungfu");
monster.save();
請注意,目前無法在同一保存中自動從數(shù)組中添加和刪除項目。 您必須在每種不同類型的數(shù)組操作之間調(diào)用 ?save
?。
要從云中刪除對象:
myObject.destroy().then(
(myObject) => {
// The object was deleted from the Moralis Cloud.
},
(error) => {
// The delete failed.
// error is a Moralis.Error with an error code and message.
}
);
您可以使用 ?unset
?方法從對象中刪除單個字段:
// After this, the ownerName field will be empty
myObject.unset("ownerName");
// Saves the field deletion to the Moralis Cloud.
// If the object's field is an array, call save() after every unset() operation.
myObject.save();
請注意,不建議使用 ?object.set(null)
? 從對象中刪除字段,這會導(dǎo)致意外功能。
對象可能與其他對象有關(guān)系。 例如,在博客應(yīng)用程序中,一個 ?Post
?對象可能有許多 ?Comment
?對象。 Moralis 支持各種關(guān)系:
一對一和一對多關(guān)系通過將 ?Moralis.Object
? 保存為另一個對象中的值來建模。
例如,博客應(yīng)用程序中的每個評論可能對應(yīng)一個帖子。
要使用單個評論創(chuàng)建新帖子,您可以編寫(可以通過?JS
?、?React
?來實現(xiàn)):
// Declare the types.
const Post = Moralis.Object.extend("Post");
const Comment = Moralis.Object.extend("Comment");
// Create the post
const myPost = new Post();
myPost.set("title", "I'm Hungry");
myPost.set("content", "Where should we go for lunch?");
// Create the comment
const myComment = new Comment();
myComment.set("content", "Let's do Sushirrito.");
// Add the post as a value in the comment
myComment.set("parent", myPost);
// This will save both myPost and myComment
myComment.save();
import { useNewMoralisObject } from "react-moralis";
export default function App() {
const postObject = useNewMoralisObject("Post");
const commentObject = useNewMoralisObject("Comment");
const makePost = async () => {
const postData = {
title: "I'm Hungry",
content: "Where should we go for lunch?",
};
const commentData = {
content: "Let's do Sushirrito.",
parent: await postObject.save(postData),
};
commentObject.save(commentData, {
onSuccess: (comment) => console.log(comment),
onError: (error) => console.log(error),
});
};
return <button onClick={makePost}>Call The Code</button>;
}
在內(nèi)部,Moralis 將引用對象僅存儲在一個位置,以保持一致性。 您還可以使用它們的 ?objectId
?鏈接對象,如下所示:
const post = new Post();
post.id = "1zEcyElZ80";
myComment.set("parent", post);
默認情況下,在獲取對象時,不會獲取相關(guān)的 ?Moralis.Object
?。 這些對象的值在被獲取之前無法被檢索,如下所示:
const post = fetchedComment.get("parent");
await post.fetch();
const title = post.get("title");
多對多關(guān)系使用 ?Moralis.Relation
? 建模。 這類似于將 ?Moralis.Object
? 的數(shù)組存儲在一個鍵中,只是您不需要一次獲取關(guān)系中的所有對象。 此外,與 ?Moralis.Object
? 方法的數(shù)組相比,這允許 ?Moralis.Relation
? 擴展到更多的對象。
例如,用戶可能有許多她可能喜歡的帖子。 在這種情況下,您可以使用關(guān)系存儲用戶喜歡的一組帖子。 要將帖子添加到用戶的“喜歡”列表中,您可以執(zhí)行以下操作:
const user = Moralis.User.current();
const relation = user.relation("likes");
relation.add(post);
user.save();
您可以從 ?Moralis.Relation
? 中刪除帖子:
relation.remove(post);
user.save();
您可以在調(diào)用 ?save
?之前多次調(diào)用 ?add
?和 ?remove
?:
relation.remove(post1);
relation.remove(post2);
user.save();
您還可以傳入一個 ?Moralis.Object
? 數(shù)組來添加和刪除:
relation.add([post1, post2, post3]);
user.save();
默認情況下,不會下載此關(guān)系中的對象列表。 您可以使用查詢返回的 ?Moralis.Query
? 獲取用戶喜歡的帖子列表。 代碼如下所示:
relation.query().find({success: function(list) {
// list contains the posts that the current user likes.
}
});
如果您只想要帖子的子集,您可以向查詢返回的 ?Moralis.Query
? 添加額外的約束,如下所示:
const query = relation.query();
query.equalTo("title", "I'm Hungry");
query.find({
success: function (list) {
// list contains post liked by the current user which have the title "I'm Hungry".
},
});
到目前為止,我們已經(jīng)使用了 ?String
?、?Number
?和 ?Moralis.Object
? 類型的值。 Moralis 還支持 ?Dates
?和 ?null
?。 您可以嵌套 JSON 對象和 JSON 數(shù)組以在單個 ?Moralis.Object
? 中存儲更多結(jié)構(gòu)化數(shù)據(jù)。 總體而言,對象中的每個字段都允許以下類型:
String
?Number
?bool
?JSON Array
?JSON Object
?Date
?Moralis.File
?Moralis.Object
?Moralis.Relation
?null
?一些例子:
const number = 42;
const bool = false;
const string = "the number is " + number;
const date = new Date();
const array = [string, number];
const object = { number: number, string: string };
const pointer = MyClassName.createWithoutData(objectId);
const BigObject = Moralis.Object.extend("BigObject");
const bigObject = new BigObject();
bigObject.set("myNumber", number);
bigObject.set("myBool", bool);
bigObject.set("myString", string);
bigObject.set("myDate", date);
bigObject.set("myArray", array);
bigObject.set("myObject", object);
bigObject.set("anyKey", null); // this value can only be saved to an existing key
bigObject.set("myPointerKey", pointer); // shows up as Pointer <MyClassName> in the Data Browser
bigObject.save();
我們不建議在 ?Moralis.Object
? 上存儲大量二進制數(shù)據(jù),例如圖像或文檔。 我們建議您使用 ?Moralis.File
? 來存儲圖像、文檔和其他類型的文件。 您可以通過實例化 ?Moralis.File
? 對象并將其設(shè)置在字段上來實現(xiàn)。
更多建議: