Click here to Skip to main content
14,021,889 members
Click here to Skip to main content
Add your own
alternative version

Stats

17.6K views
2 bookmarked
Posted 19 May 2015
Licenced CPOL

Relations in Parse.com using REST API

, 19 May 2015
Rate this:
Please Sign up or sign in to vote.
using Angular `$http` and Parse REST API to process the relations

Introduction

Parse is a cloud service platform providing a backend storage service. It offers many kinds of application program interface (API) for such as .NET, JavaScript and PHP.

In our web application we will use its REST API, this lets us interact with data on Parse from applications written in any programming language that can send an HTTP request. The request HEADER should obtain `X-Parse-Application-Id` and `X-Parse-REST-API-Key`, but for pithiness of style the following codes will pass over these messages. Besides, the `objectId` which we used very offen is a Parse built-in standard ID for one object record.

Content List:

Background

Relation between objects

Based on the classical relational database there are three (four) kinds of relationships between objects:

  • One-to-One relation: one object is associated with another object;
  • One-to-Many (Many-to-One) relation: one object has many related objects;
  • Many-to-Many relation: it represents complex relationships among many objects.

Relationships in Parse

Replying these kinds of relation, Parse provides four ways:

  • Pointer: which is suitable for one-to-one and one-to-many relationships;
  • Array: which is suitable for one-to-many and many-to-many relationships;
  • Parse Relation: which is suitable for many-to-many relationship;
  • Join Table: which is suitable for many-to-many relation.

Before going deep

Following words will discuss the usage of buiding relationships in Parse based on Public Library, In our web application we build a Publisher-Book-Author design model with two bidirectional associations as following:

In our case, there is no such relationship as One-to-One, and this situation should also be normally rare, so it would not be touched in this article.

Moreover, The official online document about Relations from Parse shows only the situation that how to solve Relations in Parse when developing an application for Android or iOS. There are many system-based functions that not fully suitable for REST API, however it tells us the logical solutions indeed.

One-to-Many Relationship

According to the Publisher-Book-Author design model, the One-to-Many relationship appears between Publisher and Book. One publisher may have no or many published books, one book may have no or only one publisher.

According to the introduction of relationships in Parse, we can use Pointer or Array to build the relation between them.

Using Pointer for One-to-Many Relationship

The starting point for building the relationship using Pointer between publisher and book objects is an association-free design model like following:

  • publisher is a property of Book, it will have no or a single value;
  • publishedBook is an inverse reference property of Publisher, it will store no or multi values.

Create/Update Pointer

Suppose we got one Publisher object and two Book objects, we want to associate all Book objects with this publisher:

<code>twoBooks.forEach( function( book) {
  $http( {
    method: 'PUT',
    url: 'https://api.parse.com/1/classes/Book/' + book.objectId,
    data: {
      publisher: {
        __type: 'Pointer',
        className: 'Publisher',
        objectId: publisher.objectId
      }
    }
  });
});
</code>

The objectId of this publisher will be saved as a property into each book object. In Pasre Core, the record of one book will be:

The record of this publisher keeps:

Retrieving Objects

If we want to get the information about the publisher of one known book:

<code>$http( {
  method: 'GET',
  url: 'https://api.parse.com/1/classes/Publisher/' + book.publisher.objectId
});</code>

Parse provides an operation include for returning multiple types of related objects in one query, when the type of this property is Pointer. In our case, the property publisher from Book is a Pointer, we can get all related publisher objects even during getting all books, without send a get request again for getting all corresponded publisher:

<code>// Get all books
$http( {
  method: 'GET',
  url: 'http://api.parse.com/1/classes/Book',
  params: { include: 'publisher'}
});</code>

If we want to get all published books from this publisher:

<code>$http( {
  method: 'GET',
  url: 'https://api.parse.com/1/classes/Book',
  params: {
    where: {
      publisher: {
        __type: 'Pointer',
        className: 'Publisher',
        objectId: publisher.objectId
      }
    }
  }
});
</code>

Delete Pointer

Suppose we want to delete all relations:

<code>twoBooks.forEach( function ( book) {
  $http( {
    method: 'PUT',
    url: 'https://api.parse.com/1/classes/Book/' + book.objectId,
    data: { publisher: { __op: 'Delete'}}
  });
});
</code>

This HTTP request will set the value of publisher Pointer<publisher> field from ooTkye1JWh to undefined, so that this book will have no publisher in the record.

Furthermore, if we didn't delete the association but delete this publisher, the records of these two books won't be changed, which means the publisher's objectId still exists in the publisher field, but this Pointer will point to none. For security reasons, it would be better delete the Pointer after deleted a publisher.

Using Array for One-to-Many Relationship

The starting point for building the relationship using Array between publisher and book objects is an association-free design model like following:

  • publisher is an inverse reference property of Book, it will have no or a single value;
  • publishedBook is a property of Publisher, it will store no or multi values in array of objects.

Compare with Pointer, our focus has been changed from book object to publisher object.

Parse provides Add, AddUnique and Remove operations to process an Array and an method to query on Array values. After made some test I found these operations are only suitable for array of strings not for array of objects, cause these queries can not travell into each single object.

Furthermore, think about if we only save the objectId instead of the whole object as the item of array, this array will be structured as a list of Pointer, which means the way of using Array will obtain all the advantages just likes the way of using Pointer.

Create/Update Array

Suppose we know one publisher which has published two books. If we want to build this relation, we should insert these two books into this publisher's publishedBooks:

Array of object

<code>$http( {
  method: 'PUT',
  url: 'https://api.parse.com/1/classes/Publisher/' + publisher.objectId,
  data: { publishedBooks: [ bookObject1, bookObject2]}
});
</code>

This publisher record will be changed to:

Array of objectId

<code>$http( {
  method: 'PUT',
  url: 'https://api.parse.com/1/classes/Publisher/' + publisher.objectId,
  data: {
    publishedBooks: {
      __op: 'AddUnique',  // can be also 'Add' or 'Remove'
      objects: [ bookObject1.objectId, bookObject2.objectId]
    }
  }
});
</code>

Retrieving Objects

Array of object

If we have got a publisher and want to get all infromation about this publisher including its published books, there will be nothing that need to do, cause this publisher record had these information about its published books already.

If we want to get the information about the publisher of one known book, we must first load all records of publisher, then manually find corresponding book from the array of publishedBooks:

<code>$http( {
  method: 'GET',
  url: 'http://api.parse.com/1/classes/Publisher'
})
  .success( function ( data) {
    var publishers = data.results;
    publishers.forEach( function ( p) {
      if ( p.publishedBooks.length > 0) {
        p.publishedBooks.forEach( function ( pb) {
          if ( pb.objectId == book.objectId) {
            console.log("Found the publisher of this book finally. Could you try to use Pointer?");
          }
        });
      }
    });
  });
</code>

Array of objectId

If we have got a publisher and want to get all infromation about this publisher including its published books:

<code>publisher.publishedBooks.forEach( function ( pb) {
  $http( {
    method: 'GET',
    url: 'https://api.parse.com/1/classes/Book/' + pb.objectId
  });
});
</code>

If we want to get the information about the publisher of one known book, we can simply send a request contained where, let Parse to work for us (Servers are always more powerful than my personal computer in my opinion):

<code>$http( {
  method: 'GET',
  url: 'https://api.parse.com/1/classes/Publisher',
  params: { where: { publishedBooks: book.objectId}}
});
</code>

Delete Array

Suppose we want to delete all relations:

<code>$http( {
  method: 'PUT',
  url: 'https://api.parse.com/1/classes/Publisher/' + publisher.objectId,
  data: { publishedBooks: { __op: 'Delete'}}
});
</code>

Many-to-Many Relationship

According to the Publisher-Book-Author design model, the Many-to-Many relationship appears between Book and Author. One book may have no or many authors books, one author may authored no or many books.

According to the introduction of relationships in Parse, we can use Parse Relation, Join Table or Array to build the relation between them.

Using Parse Relation for Many-to-Many Relationship

The starting point for building the relationship using Parse Relation between book and author objects is an association-free design model like following:

  • authors in type of Parse Relation is a property of Book, it will keep all the related authors;
  • authoredBooks in type of Parse Relation is a property of Author, it will store all the related books.

Before using the method of Parse Relation we discuss a little about what the Parse Relation really is.

If we create some books and authors as the test data in Parse, the book records with Parse Relations will be:

The author records with Parse Relations will be:

After we click one View Relations in book records, we will see that a kind of list showing on the left side, which keeps all information of the related authors:

So Parse Relations are very simily like an array of Pointer combined with its corresponding object.

Parse offers operations AddRelation and RemoveRelation for Parse Relation used to update objects. There are also some query operations, Parse has named them Relational Queries but these are only suitable for One-to-Many Relationships.

Create/Update Parse Relation

Suppose we got a book and want to relate to two authors:

<code>// add relation from book to authors
$http( {
  method: 'PUT',
  url: 'https://api.parse.com/1/classes/Book/' + book.objectId,
  data: {
    authors: {
      __op: 'AddRelation',  // or 'RemoveRelation'
      objects: [{
        __type: 'Pointer',
        className: 'Author',
        objectId: author1.objectId
      },
      {
        __type: 'Pointer',
        className: 'Author',
        objectId: author2.objectId
      }]
    }
  }
})
</code>

If we got an author and want to related to two books:

<code>// add relation from author to books
$http( {
  method: 'PUT',
  url: 'https://api.parse.com/1/classes/Author/' + author.objectId,
  data: {
    authoredBooks: {
      __op: 'AddRelation',  // or 'RemoveRelation'
      objects: [{
        __type: 'Pointer',
        className: 'Book',
        objectId: book1.objectId
      },
      {
        __type: 'Pointer',
        className: 'Book',
        objectId: Book2.objectId
      }]
    }
  }
})
</code>

Notice that if we update/delete the basic information about an author (name, birthDate, deathDate) or a book (title, year, publisher) record, do not need to change the part of Parse Relations.

Retrieving Objects

Suppose we got a book want to find all authors of this book. There are two ways that can be used:

  1. check the the authoredBooks field of author objects:

    <code> $http({
       method: 'GET',
       url: 'https://api.parse.com/1/classes/Author',
       params: {
         where: {
           authoredBooks: {
             __type: 'Pointer',
             className: 'Book',
             objectId: book.objectId
           }
         }
       }
     })
    </code>
  2. check the Parse Relation using Parse built-in operation $relatedTo:

    <code> $http({
       method: 'GET',
       url: 'https://api.parse.com/1/classes/Author',
       params: {
         where: {
           $relatedTo: {
             object: {
               __type: 'Pointer',
               className: 'Book',
               objectId: book.objectId
             },
             key: 'authors'
           }
         }
       }
     })
    </code>

If we had an author and want to find his/her books, there are same two ways that can be used:

  1. check the the authors field of book objects:

    <code> $http({
       method: 'GET',
       url: 'https://api.parse.com/1/classes/Book',
       params: {
         where: {
           authors: {
             __type: 'Pointer',
             className: 'Author',
             objectId: author.objectId
           }
         }
       }
     })
    </code>
  2. check the Parse Relation using Parse built-in operation $relatedTo:

    <code> $http({
       method: 'GET',
       url: 'https://api.parse.com/1/classes/Book',
       params: {
         where: {
           $relatedTo: {
             object: {
               __type: 'Pointer',
               className: 'Author',
               objectId: author.objectId
             },
             key: 'authoredBooks'
           }
         }
       }
     })
    </code>

Delete Parse Relation

Parse didn't allow user directly to remove the field in type of Relation, we can only use its RemoveRelation operation and a loop of request to delete all related records.

Using Array for Many-to-Many Relationship

Compare with Using Array for One-to-Many Relationship, the idea of this method is mostly like building two One-to-Many Relationships:

  • When we use array of object, we should build an array of author object then save it to authors in a book record; build an array of book object then save it into authoredBooks in an author record.
  • When we use array of objectId, we should build an array of author objectId then save it to authors in a book record; build an array of book objectId then save it to authoredBooks in an author record.

Using Join Table for Many-to-Many Relationship

Join Table is the idea from classical database. When there is a Many-to-Many relation, we combine every objectId from both sides together to build a new separate table in which the relationship is tracked:

(bookObjectId, authorObjectId) will be combined together as one key for a single record.

Create Join Table

Suppose we have two books and two authors, each author had authored one book:

<code>// author1 had authored book1
$http( {
  method: 'POST',
  url: 'https://api.parse.com/1/classes/joinBookAuthor',
  data: {
    bookObjectId: book1.objectId,
    authorObjectId: author1.objectId
  }
});
// author2 had authored book2
$http( {
  method: 'POST',
  url: 'https://api.parse.com/1/classes/joinBookAuthor',
  data: {
    bookObjectId: book2.objectId,
    authorObjectId: author2.objectId
  }
});
</code>

Update Join Table

Suppose author1 had also authored book2:

<code>$http( {
  method: 'POST',
  url: 'https://api.parse.com/1/classes/joinBookAuthor',
  data: {
    bookObjectId: book2.objectId,
    authorObjectId: author1.objectId
  }
});
</code>

Then, suppose we want to change that author1 had authored no book:

<code>$http( {
  method: 'GET',
  url: 'https://api.parse.com/1/classes/joinBookAuthor',
  params: { where: { authorObjectId: author1.objectId}}
})
  .success( function( data) {
    var joinBookAuthorRecords = data.results;
    joinBookAuthorRecords.forEach( function ( jba) {
      $http( {
        method: 'DELETE',
        url: 'https://api.parse.com/1/classes/joinBookAuthor/' + jba.objectId
      });
    });
  });
</code>

Retrieving Objects

Suppose we got book1 and want to find its all authors:

<code>$http( {
  method: 'GET',
  url: 'https://api.parse.com/1/classes/joinBookAuthor',
  params: { where: { bookObjectId: book1.objectId}}
})
  .success( function( data) {
    var joinBookAuthorRecords = data.results;
    joinBookAuthorRecords.forEach( function ( jba) {
      $http( {
        method: 'GET',
        url: 'https://api.parse.com/1/classes/Author/' + jba.authorObjectId
      });
    });
  });
</code>

Delete Join Table

The Join Table in Parse was saved as a class, Parse did not offer a function for user to delete a class.

Before ending

Based on the Parse plattform using REST API, Pointer for One-to-Many Relation and Parse Relation for Many-to-Many Relation are good choices.

We had discussed the way of using Array in Parse to set up the Publisher-Book and Book-Author relationships. Array can be used flexible, but these relations exist only logically in our application not in the database.

Join Table is the direct way for Many-to-Many Relation, but in our case, it will need to send more requests than other methods.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Bo Li (KAFFEECKO)
Student
China China
No Biography provided

You may also be interested in...

Pro

Comments and Discussions

 
PraiseAwesome Pin
Member 1213904014-Nov-15 2:36
memberMember 1213904014-Nov-15 2:36 
GeneralRe: Awesome Pin
Bo Li (KAFFEECKO)14-Nov-15 23:30
memberBo Li (KAFFEECKO)14-Nov-15 23:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web06 | 2.8.190417.4 | Last Updated 19 May 2015
Article Copyright 2015 by Bo Li (KAFFEECKO)
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid