Parse.js + AngularJS app relational data query issue - parsing

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

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.

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

Related

Querying Relationships in Laravel 5.2

I am having issues trying to query an Eloquent relationship.
I have 2 tables
tbl_deals
id
deal_id
merchant_id
tbl_merchants
id
merchant_id
merchant_url_text
I defined a deal model as
class deal extends Model
{
public function merchant() {
return $this->hasOne('App\merchant', 'merchant_id', 'merchant_id');
}
}
Now, I want to query all deals based where merchant_url_text = a variable in my controller
Here's what I am trying
$deals = deal::with('merchant')->get(); //Retrieving all the deals with merchants
If I return $deals its giving me all deals with merchant relationship.
How do I constraint the deals by saying where merchant_url_text = $variable
I am trying
return $deals->where('merchant_url_text', $merchant_url_text)->get();
but it is giving me an error saying :
"Missing argument 1 for Illuminate\Support\Collection::get(), called in ..."
I tried to lookup the documentation for querying relationships in Laravel Docs. It talks about this example
$user = App\User::find(1);
$user->posts()->where('active', 1)->get();
In this case, its trying to get the first user and finding corresponding posts related to the user.
In my case I want to filter from all deals, the deals that have merchant_url_text = a specific variable in my controller.
Any help on how I can achieve this?
Thanks
Try the following code :
$specific_merchant_url_text = "i don't know";
$deals_with_specific_merchant_url_text = [];
$deals = deal::with('merchant')->get();
foreach($deals as $deal)
if( $deal->merchant->merchant_url_text==$specific_merchant_url_text)
array_push($deals_with_specific_merchant_url_text, $deal);
So you get array of deals with specific merchant url text in deals_with_specific_merchant_url_text.
Another approach using DB object :
$deals = DB::table('deals')
->join('merchants', 'deals.merchant_id', '=', 'merchants.id')
->select('deals.*')
->where('merchants.merchant_url_text', $merchant_url_text)
->get();
Yours with raw :
$deals = deal::selectRaw('tbl_deals.*')
->Join('merchants','deals.merchant_id','=','merchants.merchant_id')
->where('merchants.merchant_url_text', '=', $merchant_url_text) ->get();
Hope this helps.
With takes a callback. This will bring back all deals but only eager load merchants that match.
$deals = Deal::with(['merchant' => function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
}])->get();
Flip-side: if you only want deals with a matching merchant, use where has.
$deals = Deal::whereHas('merchant', function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
})->get();
If you want both, chain them:
$deals = Deal::whereHas('merchant', function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
})->with(['merchant' => function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
}])->get();
I capitalized deal because it's standard. It wasn't capitalized in your example.
You can use query builder join query .
DB::table('tbl_merchants')
->join('tbl_deals', 'tbl_merchants.merchant_id', '=','tbl_deals.merchant_id')
->where('tbl_merchants.merchant_url_text',$merchant_url_text)
->get();

parse.com selecting from join table

Just wondering am I doing this correctly or is there a better way.
I have 3 tables, Game, User and UserGame. The UserGame is a join table has pointers to both Game and User tables.
The following script returns all the games that the user has joined.
var Game = Parse.Object.extend("Game");
var UserGame = Parse.Object.extend("UserGame");
var innerQuery = new Parse.Query(Game);
var query = new Parse.Query(UserGame);
query.equalTo("user", user);
query.matchesQuery("game", innerQuery);
query.include("game");
query.find({
I am now trying to return the games that the user has not joined. I tried the reverse of the above query but it does not work. Any ideas?
Also is there a better solution than using the join table above, should I just add a list of game pointers to the user table?
This is userful (and not easily accessible from the website)
https://parse.com/docs/js/symbols/Parse.Query.html
What you're trying to do seems like a good usecase of .noContainerIn([results of the first query]) or .doesNotMatchKeyInQuery
matchesKeyInQuery in your first example seems simpler to use BTW
I have used a table that has two pointers inside it too.I'm going to explain what I did simplified, and adpating it to your case:
1.Build a query with your object Game,to get an array of all games that exists in this table:
var Game = Parse.Object.extend("Game");
var query = new Parse.Query(Game);
query.find({
success: function(arrayGames) {
//store this array to manage later
},
error: function(user, error) {
alert("There is not stored games");
}
});
2. Get the user you want to compare to this games stored that points in the table UserGame, and make a Query for each element of the previous got array:
var UserGame = Parse.Object.extend("UserGame");
var query = new Parse.Query(UserGame);
var currentUser = Parse.User.current();
var currentGame;
for(var i=0; i<arrayGames.length ;i++){
currentGame=arrayGames[i];
query.equalTo("Game", currentGame);
query.notEqualTo("User", currentUser);
query.find({
success: function(foundGames) {
//you have got an array with the games not joined to this user
},
error: function(user, error) {
alert("There are not joined games ");
}
});
}
Hope it helps, ask me if you need more details ;)

LINQ to Entities query with join inside method for use in MVC app

In my Person table is a RequestedLocation column which stores location IDs. The IDs match the LocationId column in the Locations table, the Locations table also has the text location names, in the LocatioName column.
In my view, I need to display the string LocationName in the view which has the Person model passed to it. The view will be displaying a List of people in a telerik grid. CUrrently it works great, except the RequestedLocation column is all integers.
I am populating all my grids with methods containing LINQ queries. Here is the method that currently works:
public List<Person> GetPeople()
{
var query = from p in _DB.Person.ToList()
select p;
return query.ToList();
}
Here is the regular SQL query that works, and I need to convert into LINQ:
SELECT ApplicantID
,FirstName
,LastName
,MiddleName
,DateofBirth
,Gender
,RequestedVolunteerRole
,RequestedVolunteerLocation
,l.LocationName
FROM Form.Person p
JOIN dbo.Location l ON p.RequestedVolunteerLocation = l.LocationID
Order BY ApplicantID
Here is my attempt to convert to LINQ:
public List<NewApplicantViewModel> GetPeople()
{
var query = from pl in _DB.Person.ToList()
join l in _Elig_DB.Locations.ToList() on pl.RequestedVolunteerLocation equals l.LocationID
select new
{
pl.RequestedVolunteerLocation = l.LocationName
};
return query.ToList();
The number of errors I get from this are numerous, but most are along the lines of:
Cannot convert from type Annonymous to Type List<NewAPplicantModel>
and
Invalid annonymous type declarator.
Please help, and thank you for reading my post.
Oh, and I have only been programming for a couple months, so if I am going about this all wrong, please let me know. Only thing I have to stick with is the table structure because it is an existing app that I am updating, and changing the location or person tables would have large consequences.
public List<NewApplicantViewModel> GetPeople()
{
var query = from pl in _DB.Person
join l in _Elig_DB.Locations on pl.RequestedVolunteerLocation
equals l.LocationID
select new NewApplicantViewModel
{
LocationName = l.LocationName,
otherPropery = p.Property
};
return query.ToList();
}
Beware of calling _DB.Person.ToList() it will load all persons from DB because ToList() immediately executes the query and the join would be performed in memory (not in DB).
The reason you are getting an error is you are projecting an anonymous type
select new
{
pl.RequestedVolunteerLocation = l.LocationName
};
Instead, you need to project a NewApplicantViewModel
select new NewApplicantViewModel
{
RequestedVolunteerLocation = l.LocationName
};

inserting data into a Many to many junction table with payload in entity framework

I have a Cake table and an ingredient table a cake is made of many ingredients and an ingredient can be in many cakes so I've created a many to many mapping with join table cake_ingredients. In addition however different quantities of each ingredient is used for each cake. For example in cake flavor A you could require 1.25kg of flour while in cake flavor B you require 1.5kg. Due to the different quantities of ingredients the cost for each ingredient used in each cake will be different. Therefore my join table needs to be with payload, the additional columns are quantity and cost. I've created this relationship successfully by following this tutorial.
I can add cake_id and ingredient_id successfully to the join table by modifying the following block of code that I got from the above tutorial
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.Courses.Select(c => c.CourseID));
foreach (var course in db.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
}
Trouble comes in inserting quantity and cost (this will be calculated).
How do I go about this? I figure if someone could help me insert quantity I'll be able to insert the calculated cost.

How to join multiple tables using LINQ-to-SQL?

I'm quite new to linq, so please bear with me.
I'm working on a asp.net webpage and I want to add a "search function" (textbox where user inputs name or surname or both or just parts of it and gets back all related information). I have two tables ("Person" and "Application") and I want to display some columns from Person (name and surname) and some from Application (score, position,...). I know how I could do it using sql, but I want to learn more about linq and thus I want to do it using linq.
For now I got two main ideas:
1.)
var person = dataContext.GetTable<Person>();
var application = dataContext.GetTable<Application>();
var p1 = from p in Person
where(p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1]))
select new {Id = p.Id, Name = p.Name, Surname = p.Surname}; //or maybe without this line
//I don't know how to do the following properly
var result = from a in Application
where a.FK_Application.Equals(index) //just to get the "right" type of application
//this is not right, but I don't know how to do it better
join p1
on p1.Id == a.FK_Person
2.) The other idea is just to go through "Application" and instead of "join p1 ..." to use
var result = from a in Application
where a.FK_Application.Equals(index) //just to get the "right" type of application
join p from Person
on p.Id == a.FK_Person
where p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1])
I think that first idea is better for queries without the first "where" condition, which I also intended to use. Regardless of what is better (faster), I still don't know how to do it using linq. Also in the end I wanted to display / select just some parts (columns) of the result (joined tables + filtering conditions).
I really want to know how to do such things using linq as I'll be dealing also with some similar problems with local data, where I can use only linq.
Could somebody please explain me how to do it, I spent days trying to figure it out and searching on the Internet for answers.
var result = from a in dataContext.Applications
join p in dataContext.Persons
on p.Id equals a.FK_Person
where (p.Name.Contains("blah") || p.Surname.Contains("foo")) && a.FK_Application == index
select new { Id = p.Id, Name = p.Name, Surname = p.Surname, a.Score, a.Position };
Well as Odrahn pointed out, this will give you flat results, with possibly many rows for a single person, since a person could join on multiple applications that all have the same FK. Here's a way to search all the right people, and then add on the relevant application to the results:
var p1 = from p in dataContext.Persons
where(p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1]))
select new {
Id = p.Id, Name = p.Name, Surname = p.Surname,
BestApplication = dataContext.Applications.FirstOrDefault(a => a.FK_Application == index /* && ???? */);
};
Sorry - it looks like this second query will result in a roundtrip per person, so it clearly won't be scalable. I assumed L2S would handle it better.
In order to answer this properly, I need to know if Application and Person are directly related (i.e. does Person have many Applications)? From reading your post, I'm assuming that they are because Application seems to have a foreign key to person.
If so, then you could create a custom PersonModel which will be populated by the fields you need from the different entities like this:
class PersonModel
{
string Name { get; set; }
string Surname { get; set; }
List<int> Scores { get; set; }
List<int> Positions { get; set; }
}
Then to populate it, you'd do the following:
// Select the correct person based on Name and Surname inputs
var person = dataContext.Persons.Where(p => p.Name.Contains("firstname") || p.Name.Contains("surname")).FirstOrDefault();
// Get the first person we find (note, there may be many - do you need to account for this?)
if (person != null)
{
var scores = new List<int>();
var positions = new List<int>();
scores.AddRange(person.Applications.Select(i => i.Score);
positions.AddRange(person.Applications.Select(i => i.Position);
var personModel = new PersonModel
{
Name = person.Name,
Surname = person.Surname,
Scores = scores,
Positions = positions
};
}
Because of your relationship between Person and Application, where a person can have many applications, I've had to account for the possibility of there being many scores and positions (hence the List).
Also note that I've used lambda expressions instead of plain linqToSql for simple selecting so that you can visualise easily what's going on.

Resources