15.关系Relations

关系

有三种关系。一对一关系使一个对象能够与另一个对象相关联。一对多关系使一个对象具有许多相关对象。最后,多对多关系使许多对象之间的复杂关系成为可能。

在Parse中建立关系有四种方式:

一对多关系(One-to-Many)

当您考虑一对多关系以及是否实现指针或数组时,有几个要考虑的因素。首先,这种关系涉及多少对象?如果关系的“多”一方可能包含非常多(大于100个)的对象,则必须使用指针。如果对象的数量很少(少于100个),那么数组可能更方便,特别是作为父对象,您需要同时获取其所有相关对象(一对多关系中的“多”)时。

1.使用指针

假设我们有一个游戏app。游戏记录玩家每次玩的成绩和成就。在Parse中,我们可以将这些数据存储在一个Game对象中。如果app非常成功,每个玩家将在系统中存储数千个Game对象。对于这样的情况,如果关系的数量可以任意大,最好使用指针。

假设在这个游戏app中,每个Game对象都与一个Parse User相关联。我们可以这样实现:

var game = new Parse.Object("Game");
game.set("createdBy", Parse.User.current());

我们可以获取由Parse User创建的所有Game对象的查询:

var query = new Parse.Query("Game");
query.equalTo("createdBy", Parse.User.current());

而且,如果我们想要找到创建特定Game对象的Parse User,可以使用createdBy关键字查找:

// say we have a Game object
var game = ...

// getting the user who created the Game
var user = game.get("createdBy");

对于大多数情况,指针将是实现一对多关系的最佳选择。

2.使用数组

当我们知道一对多关系中涉及到的对象的数量将会很小时,数组是理想的。数组的includeKey参数具备一些优势。提供这个参数能够同时获得“一对多”关系中所有的“多”对象和“一”对象。然而,如果关系中涉及的对象数量很多,则响应时间会很慢。

假设在游戏中,玩家能够跟踪他们的角色在游戏中所积累的所有武器,而且只能有十几种武器。在这个例子中,我们知道武器的数量不会很大。我们还可以让玩家指定武器显示的顺序。此时,数组是理想的,一是因为这个数组较小,二是因为我们也希望保留用户每次玩游戏时所设定的顺序:

我们首先在Parse User对象上创建一个列weaponsList。

现在我们来储存一些Weapon对象到weaponsList中:

// let's say we have four weapons
var scimitar = ...
var plasmaRifle = ...
var grenade = ...
var bunnyRabbit = ...

// stick the objects in an array
var weapons = [scimitar, plasmaRifle, grenade, bunnyRabbit];

// store the weapons for the user
var user = Parse.User.current();
user.set("weaponsList", weapons);

后来,如果我们想要检索Weapon对象,只需要一行代码:

var weapons = Parse.User.current().get("weaponsList")

有时,我们希望在获取一对多关系中“一”对象的同时获取其中的“多”对象。一个技巧是使用includeKey(Android中为include)参数,每当我们使用Parse Queries在获取Parse User对象的同时,也可以获取Weapon对象数组(存储在weaponsList列中):

// set up our query for a User object
var userQuery = new Parse.Query(Parse.User);

// configure any constraints on your query...
// for example, you may want users who are also playing with or against you

// tell the query to fetch all of the Weapon objects along with the user
// get the "many" at the same time that you're getting the "one"
userQuery.include("weaponsList");

// execute the query
userQuery.find({
  success: function(results){
    // results contains all of the User objects, and their associated Weapon objects, too
  }
});

你也可以通过“多”对象获得一对多关系中的“一”对象。例如,如果我们想要找到所有拥有给定Weapon的Parse User对象,查询约束条件可以这样写:

// add a constraint to query for whenever a specific Weapon is in an array
userQuery.equalTo("weaponsList", scimitar);

// or query using an array of Weapon objects...
userQuery.containedIn("weaponsList", arrayOfWeapons);

多对多关系(Many-to-Many)

假设我们有一个读书app,我们想对Book对象和Author对象进行建模。我们知道,一个给定的作者可以写很多书,一本书可以有多个作者。这是一个多对多关系场景,您必须在数组、Parse Relations或创建自己的Join Table之间进行选择。

这里的关键点在于您是否要附加元数据到两个实体之间的关系中。

如果没有,Parse Relations或使用数组将是最直接的选择。一般来说,使用数组将获得更高的性能、更少的查询量。如果多对多关系的任何一方可能超过100个对象,那么,跟指针在一对多关系中更好的原因一样,Parse Relations或Join Table将是更好的选择。

另一方面,如果要将元数据附加到关系中,则需要创建一个单独的表(“Join Table”)来存放关系的两端。记住,这是关系的信息,而不是关系的任何一方的对象。您可能对使用Join Table方法附加元数据的一些示例感兴趣,包括:

1.使用Parse Relations

使用Parse Relations,我们可以创建一个Book和几个Author对象之间的关系。在数据浏览器中,您可以在Book对象上创建一个类型关系列,并将其命名为authors。

之后,我们可以将一些作者与本书联系起来:

// let’s say we have a few objects representing Author objects
var authorOne = ...
var authorTwo = ...
var authorThree = ...

// now we create a book object
var book = new Parse.Object("Book");

// now let’s associate the authors with the book
// remember, we created a "authors" relation on Book
var relation = book.relation("authors");
relation.add(authorOne);
relation.add(authorTwo);
relation.add(authorThree);

// now save the book object
book.save();

要获取写书的作者列表,可以创建一个查询:

// suppose we have a book object
var book = ...

// create a relation based on the authors key
var relation = book.relation("authors");

// generate a query based on that relation
var query = relation.query();

// now execute the query

也许你还想得到某个作者撰写的所有书籍的清单。您可以创建一种略有不同的查询来获得这个反关系:

// suppose we have a author object, for which we want to get all books
var author = ...

// first we will create a query on the Book object
var query = new Parse.Query("Book");

// now we will query the authors relation to see if the author object we have
// is contained therein
query.equalTo("authors", author);

2.使用Join Tables

在某些情况下,我们想要获得关系上更多的信息。例如,假设我们正在建模用户之间的关注/被关注关系:给定的用户可以关注另一个用户,就像流行的社交网络一样。在我们的app中,我们不仅想知道用户A是否关注用户B,而且我们也想知道用户A何时开始关注用户B。此信息不能包含在Parse Relations中。为了跟踪这些数据,您必须创建一个单独的表来记录这个关系。我们建立表Follow,它有一from列和一to列,每一列都有一个指向Parse User的指针。除了关系之外,您还可以添加一个Date类型的列date。

现在,当你想保存两个用户之间的关系时,在Follow表中创建一行数据,相应的填写from,to和date字段:

var otherUser = ...

// create an entry in the Follow table
var follow = new Parse.Object("Follow");
follow.set("from", Parse.User.current());
follow.set("to", otherUser);
follow.set("date", Date());
follow.save();

如果想找到我们正在关注的所有人,我们可以在Follow表上执行查询:

var query = new Parse.Query("Follow");
query.equalTo("from", Parse.User.current());
query.find({
  success: function(users){
    ...
  }
});

通过to字段可以轻松地查找到关注当前用户的所有用户:

// create an entry in the Follow table
var query = new Parse.Query("Follow");
query.equalTo("to", Parse.User.current());
query.find({
  success: function(users){
    ...
  }
});

3.使用数组

数组在多对多关系中的使用方式与在一对多关系的方式大致相同。关系一侧的所有对象都将包含一个Array列,其中包含关系另一侧的若干对象。

假设我们有一个阅读app ,包含了Book和Author对象。该Book对象包含一个Author对象数组(键名authors)。数组非常适合这种情况,因为一本书不太可能有超过100个作者。正是基于此,我们将这个Author数组放在Book对象中。毕竟,一个作者可以写出100多本书。

我们这样保存Book和Author之间的关系:

// let's say we have an author
var author = ...

// and let's also say we have an book
var book = ...

// add the author to the authors list for the book
book.add("authors", author);

由于作者列表是一个数组,所以在获取Book对象时应该使用includeKey(Android上使用include)参数,以便Parse在返回book对象时同时返回其所有作者:

// set up our query for the Book object
var bookQuery = new Parse.Query("Book");

// configure any constraints on your query...
// tell the query to fetch all of the Author objects along with the Book
bookQuery.include("authors");

// execute the query
bookQuery.find({
  success: function(books){
    ...
  }
});

在此,获取给定Book对象的所有Author非常直观:

var authorList = book.get("authors")

最后,假如你想找到包含某个Author的所有Book对象,只需要在查询上带上约束条件:

// set up our query for the Book object
var bookQuery = new Parse.Query("Book");

// configure any constraints on your query...
bookQuery.equalTo("authors", author);

// tell the query to fetch all of the Author objects along with the Book
bookQuery.include("authors");

// execute the query
bookQuery.find({
  success: function(books){
    ...
  }
});

一对一关系(One-to-One)

在Parse中,一对一关系非常适用于需要将一个对象分割成两个对象的情况。这些情况应该很少,但也有两个例子:

  • 1.限制某些用户数据的可见性。在这种情况下,可以将对象拆分为两个,其中对象的一部分数据对其他用户可见,而关联对象的部分数据则对本用户是私有的(并通过ACL保护)。

  • 2.拆分对象的大小。在这种情况下,原始对象超过了对象允许的最大大小128KB,因此需要创建辅助对象来存放额外的数据。通常应该设计好数据模型以避免这样庞大的对象,而不是分开它们。如果不能避免这样做,还可以考虑将大数据存储在Parse文件中。

感谢您阅读至此。我们为复杂性道歉。一般而言,数据建模关系是一个难题。但要看到光明的一面:它比人与人的关系还是要简单一些。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,204评论 0 4
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • REST API 可以让你用任何支持发送 HTTP 请求的设备来与 Parse 进行交互,你可以使用 REST A...
    Caroline嗯哼阅读 1,987评论 0 0
  • 读大学有什么用,还不如早点出来打工?听你这话,肯定没读过大学。 记得快毕业那一年12月,最后半年学校要求大家实习。...
    不爱笑的猫i阅读 398评论 0 2