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文件中。

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

你可能感兴趣的:(15.关系Relations)