3

I have two parse classes; Companies and Ratings. It is a one to many relationship. Companies can have many Ratings. This is the statement I would perform in SQL:

SELECT Companies.name, Ratings.rating
FROM Companies
INNER JOIN Ratings
ON Ratings.name_id = Companies.name_id
ORDER BY Companies.name

I want the equivalent of this in Parse, but I'm not sure of how to go about it. Here is what I've currently tried:

function getRatings() {
  var tableA = new Parse.Query(Companies);
  var tableB = new Parse.Query(Ratings);

  tableB.equalTo("name_id", tableA.name_id);
  tableB.find({
    success: function(results) {
      $scope.$apply(function() {
        $scope.companies = results.map(function(obj) {
          return {
            id: obj.get("name_id"), 
            name: obj.get(tableA.name), 
            rating: obj.get("rating"), 
            parseObject: obj
          };
        });
      });
    },
    error: function(error) {
      alert("Error: " + error.code + " " + error.message);
    }
  });
}

I am calling this function when the controller loads. This code displays the rating in my output, but not the name of the company.

I am trying to get all the companies listed in the companies object, then pair them with all the ratings they have in the ratings object. Their common key is name_id. This is the code I am using within my Angular view:

<div class="span12">
    <div ng-repeat="company in companies | filter: query | orderBy: orderList" 
         class="well company-description">
        <h1>{{company.name}}</h1>
        <h3>Rating: {{company.rating}}</h3>
    </div>
</div>

If I am way off base on this, please let me know

2 Answers 2

5

Get rid of the name_id column in the Ratings class. This isn't how you're supposed to define relationship using Parse.

There are a couple of options for you to choose.

Option 1

Using the Parse data browser, add a new column under the Companies class, called ratings. It should be a column of type Relation and point to Ratings as the target class. (Let me know if you need more information on how to do this.)

Then, when you create or edit a company, add ratings as follows:

var Companies = Parse.Object.extend("Companies");
var Ratings = Parse.Object.extend("Ratings");

var company = new Companies({name: "Some Company"});
company.relation("ratings").add(new Ratings({stars: 5}));
company.save();

Then, when querying Companies, do so as follows:

new Parse.Query(Companies).find({
    success: function(companies) {
        for (var i = 0; i < companies.length; i++) {
            companies[i].relation("ratings").query().find({
                success: function(ratings) {
                    // Finally, I have the ratings for this company
                }
            }
        }
    }
});

Option 2

Using the Parse data browser, add a new column under the Companies class, called ratings. It should be a column of type Array.

Then, when you create or edit a company, add ratings as follows:

var Companies = Parse.Object.extend("Companies");
var Ratings = Parse.Object.extend("Ratings");

var company = new Companies({
    name: "Some Company",
    ratings: [new Ratings({stars: 5})]
});
company.save();

Then, when querying Companies, do so as follows:

new Parse.Query(Companies).include("ratings").find({
    success: function(companies) {
        // Yay, I have access to ratings via companies[0].get("ratings")
    }
});

include("ratings") tells Parse to include the actual objects, rather than pointers to objects for the given key.

Conclusion

Option 1 is better if you are expecting to have a large amount of ratings for each company, and if you don't always plan on retrieving all the ratings each time you query the companies.

Option 2 is better if the number of ratings for each company is relatively small, and you always want ratings to come back when you query companies.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you Lukas for your post, it makes a lot more sense now the way you have described it. However, I've been trying the second option you listed here, but I seem to be getting back incorrect results. It is returning the entire ratings object, and my rating is being output like this: '[{"stars":5,"objectId":"V2NZoe64G2","createdAt":"2013-03-08T18:54:05.372Z","updatedAt":"2013-03-08T18:54:05.372Z"}]' using ratings.stars returns me undefined.
So you only want the stars property, instead of the entire ratings object?
TBH, I'm not sure. I don't exactly understand what is going on here. I think the ratings for that company are being added to the ratings object correct? What I want to do eventually is retrieve the average rating... add all the stars up, divide by total amount of ratings.
I've been trying to get Option 1 running. However, whenever I create a rating manually in the browser, the relation doesn't seem to save correctly. It saves in in the Ratings object, but when I View Relation it does not appear. And when I try to use the code for Option 1 to create an object, I receive the following error in the console: Uncaught You can't add an unsaved Parse.Object to a relation.
1

I found out how to resolve the Uncaught You can't add an unsaved Parse.Object to a relation. error.

    var addRating = new Ratings({stars: rating}); // save rating first, then associate it with a company
    addRating.save({
        success: function() {
            var addCompany = new Companies({name: name});
            addCompany.relation("ratings").add(addRating);
            addCompany.save();
        }
    });

The rating has to be saved first, then the company relation can be added later on... makes sense, but took me awhile to figure it out! :S

1 Comment

Good to know! Have you run into a lot of headaches with angular and parse.com? I'm asking because I'm currently comparing BaaS options.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.