对象关系
对象关系有三种。一对一关系,即一个对象关联另一个对象的关系;一对多关系,即多个对象关联一个对象的关系;多对多关系,即多个对象中复杂的关系。
有4种方法在Parse中建立对象关系:
一对多关系
如果你想使用指针或数组来实现一对多的关系,有几个因素需要考虑。首先要考虑,这种关系中涉及多少个对象,如果子对象数量多余100个,推荐使用一对多的关系,如果少于100个,使用数组可能更方便,尤其是你想根据父对象一次获取所有子对象的时候。
使用指针
假设我们有一个游戏应用,要跟踪玩家的分数和成就,在Parse中,我们可以把这些数据保存在Game对象中。如果这个游戏非常成功,所有玩家可能会存储几千个Game对象到系统中,对于这样的情况,子对象的数量可能任意大,指针就是最合适的选择。
要实现这样的游戏应用,我们要确保每个Game对象都关联一个用户对象,我们可以这样实现:
var game = new Parse.Object("Game");game.set("createdBy", Parse.User.current());
我们可以通过匹配用户对象来查询用户的所有Game对象:
var query = new Parse.Query("Game");query.equalTo("createdBy", Parse.User.current());
如果要获取Game对象的创建者,可以通过指针字段获取:
// Game对象var game = ...// Game对象创建者var user = game.get("createdBy");
大多数情况下,实现一对多的关系,使用指针都是最好的选择。
使用数组
当我们已知子对象的数量很少时,使用数组是个好办法。includeKey参数提供一些便捷性,可以让你在获得父对象的同时获得所有的子对象。不过,如果子对象数量很大的话,会造成响应时间增长。
假设在我们的游戏中,要跟踪玩家在游戏中积累的武器,并且要限制武器的数量。我们已知武器的数量不大,并且需把用户的武器按顺序显示在屏幕中。在这个例子中,使用数组就是很好的方法。
现在让我们来为用户对象创建一个weaponsList(武器列表)字段,然后存储一些Weapon(武器)到weaponsList中:
// 假设我们有4个武器对象var scimitar = ...var plasmaRifle = ...var grenade = ...var bunnyRabbit = ...//插入武器到对象var weapons = [scimitar, plasmaRifle, grenade, bunnyRabbit];// 为用户设置weaponsListvar user = Parse.User.current();user.set("weaponsList", weapons);
如果以后想再获得Weapon对象,只需要一行代码即可:
var weapons = Parse.User.current().get("weaponsList")
有时我们fetch一个对象,想要同时拉取父对象的子对象,只需要为Parse.Query添加includeKey即可:
// 用户对象的查询对象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// 告诉查询对象想要同时拉取到哪个子对象userQuery.include("weaponsList");// 执行查询userQuery.find({success: function(results){// results contains all of the User objects, and their associated Weapon objects, too}});
你也可以通过子对象获取父对象,比如,我们要查询哪个用户具有给定的子对象,我们可以为查询对象增加一个这样的条件:
// 增加武器列表是否包含某武器的条件userQuery.equalTo("weaponsList", scimitar);// 或者传入武器数组查找包含多个武器的用户userQuery.containedIn("weaponsList", arrayOfWeapons);
多对多关系
现在我们来处理多对多关系。假设我们有一个阅读应用,我们需要构建Book对象和Author对象,一个作者可以写多本书,并且一本书可以有多个作者,这就是一个多对多关系的场景,你必须从数组、对象关系、指针三个方案中做出选择。
决策的关键点在于你是否有父子对象以外的信息要保存。
如果没有,使用关系对象或者使用数组是最简单的方案。通常,使用数组会产生更高的并发和较少的请求。
如果有,那么使用指针指向关联对象更合适。
使用Parse.Realtion
使用Parse.Relation,我们可以在Book对象和一些Author对象中建立关联。你可以在数据浏览器中,在Book对象上创建一个relation类型的authors字段。然后,我们可以为Book对象关联一些author:
// 假设有这么几个author对象var authorOne = ...var authorTwo = ...var authorThree = ...// 构建book对象var book = new Parse.Object("Book");// 为book对象关联作者var relation = book.relation("authors");relation.add(authorOne);relation.add(authorTwo);relation.add(authorThree);// 保存book.save();
要获取一本书的作者列表,可以创建一个查询:
// 假设有一个book对象var book = ...// 通过relation方法获取relation对象var relation = book.relation("authors");// 通过relation对象构建查询对象var query = relation.query();// 执行查询即可
假如你想获取一个作者参与编辑过的书籍列表, 只需要为查询对象增加条件即可:
// 假设有一个作者对象var author = ...// 构建查询对象var query = new Parse.Query("Book");// 增加约束条件query.equalTo("authors", author);
使用指针
假设我们要在用户间构建一个following(我关注的)/follower(关注我的)关系,一个用户可以关注多个用户,就像社交平台一样。在我们的应用中,我们不只需要知道谁关注了谁,还需要知道是什么时候关注的。要有序的记录这些数据,你必须创建一个独立的class表,这个表我们将命名为Follow,它有form字段和to字段,都是指向一个用户的指针。除了这些,你还可以添加一个Date类型的字段date用来记录时间。
现在,如果你想保存两个用户的关注信息,只需要在Follow表中设置from、to和date的值即可:
var otherUser = ...// 构建Follow对象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字段查找即可:
// 构建查询对象var query = new Parse.Query("Follow");query.equalTo("to", Parse.User.current());query.find({success: function(users){...}});
使用数组
在多对多关系中使用数组和在一对多关系中使用数组很像,关系一方的对象用一个数组字段包含另一方的一些对象。
还是假设我们有一个阅读应有,有Book和Author两个对象,Book对象有一个authors数组字段包含了Book的所有Author,数组在这里就非常合适,因为一本书的作者不会超过100个人。不过一个作者可能会写100本以上的书。
下面是我们保存Book和Author关系的示例:
// 假设有一个作者对象var author = ...// 假设有个Book对象var book = ...// 把author对象添加到authors数组中book.add("authors", author);
因为authors是一个数组,你应该在查询Book的时使用includeKey参数把author包含进来,以便服务器返回Book对象时同时包含作者:
// 构建Book查询对象var bookQuery = new Parse.Query("Book");// 告诉查询对象包含authors字段bookQuery.include("authors");// execute the querybookQuery.find({success: function(books){...}});
要根据拿到的Book对象获取authors数组可以直接使用get方法:
var authorList = book.get("authors")
最后,如果你想根据一个用户对象,查询用户所有参与编辑过的书,直接使用include方法即可:
// 构建查询对象var bookQuery = new Parse.Query("Book");// 增加约束条件bookQuery.equalTo("authors", author);// 告诉查询对象要包含作者bookQuery.include("authors");// 执行查询bookQuery.find({success: function(books){...}});
一对一关系
在某些情况下,要将一个对象分成两个对象,一对一关系就很合适。这种例子可能很少,但是也有如下两个例子:
- 限制某些用户数据的可见。在这个场景中,你要把对象一分为二,其中一部分数据对其他用户可见,关联的另一部分数据对其他用户不可见,并且被ACL保护。
- 分割对象大小。在这个场景中,你的原始对象大小超过了允许的128K,所以你决定创建第二个对象存储额外的数据。所以设计好你的数据模型很重要,可以避免对象过大要分割对象。如果你无法避免这样做,你可以考虑将大文件存储到Parse.File中。
最后,感谢你阅读了这么多,我们为这复杂程度向你致歉。虽然对象关系是比较难的部分,但是也有好的一面:
它可比人际关系简单多了。
